SlideShare uma empresa Scribd logo
1 de 10
Baixar para ler offline
9 . Arrastar e Soltar
 Habilitando Arrastar e Soltar
 Suporte a tipos Customizados de Arrastamento
 Controlando a Área de Transferência
“Drag and Drop”, ou Arrastar e soltar é uma forma moderna e intuitiva de transferir informação em uma aplicação ou
entre aplicações diferentes. È geralmente fornecida em adição ao suporte a clipboard para mover e copiar dados.
Neste capítulo, veremos como adicionar suporte a arrastar e soltar a uma aplicação e como controlar formatos
customizados. Então mostraremos como reusar o código do arrastar e soltar para adicionar suporte ao clipboard.
Esta reutilização de código é possível porque ambos mecanismos são baseados em QMimeData, uma classe que
pode fornecer dados em diversos formatos.
Habilitando Arrastar e Soltar
Drag e Drop envolve duas ações distintas: Arrastar e soltar algo. Widgets do Qt podem servir como pontos de
arrastamento, ou como pontos de soltura, ou como ambos.
Nosso primeiro exemplo mostra como fazer uma aplicação Qt aceitar um arrastamento iniciado por outra aplicação.
A aplicação Qt é uma janela principal como um QTextEdit como seu widget central. Quando o usuário carrega
um arquivo texto da Área de Trabalho ou por um explorador de arquivos e o solta na aplicação, a aplicação carrega o
arquivo dentro de QTextEdit.
Aqui está a definição da classe MainWindow do exemplo:
Class MainWindow : public QMainWindow
{
Q_OBJECT;
public:
MainWindow();
protected:
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
private:
bool readFile(const QString &fileName);
QTextEdit *textEdit;
};
A classe MainWindow reimplementa dragEnterEvemt() e dropEvent() de QWidget. Já que o
propósito desse exemplo é mostrar a funcionalidade arrastar e soltar, a maioria da funcionalidade que esperaríamos
ver em uma classe de janela principal foi omitida.
MainWindow::MainWindow()
{
textEdit = new QTextEdit;
setCentralWidget (textEdit);
textEdit->setAcceptDrops(false);
setAcceptDrops(true);
setWindowTitle(tr(“Text Editor”));
}
No construtor, criamos um QTextEdit e o setamos como o widget central. Por padrão, QTextEdit aceita
arrastes textuais de outras aplicações, e se o usuário solta um arquivo dentro dele, o nome do arquivo será inserido
no texto. Já que eventos de drop são propagados do filho para o pai, desabilitando a funcionalidade de soltar no
QTextEdit e a habilitando na janela principal obtemos os eventos de drop para a janela inteira em
MainWindow.
void MainWindow::dragEnterEvent (QDragEnterEvent *event)
{
if(event->mimeData()->hasFormat(“text/uri-list”))
event->acceptProposedAction();
}
O dragEnterEvent()é chamado a qualquer momento em que o usuário arrasta um objeto para dentro do
widget. Se chamarmos acceptProposedAction() no evento, indicamos que o usuário pode soltar o objeto
carregado no widget. Por padrão, o widget não aceitaria o objeto. Qt automaticamente muda o cursor para indicar ao
usuário quando o widget é considerado um ponto de soltura.
Aqui queremos que o usuário seja autorizado a carregar arquivos, mas nada mais. Para tal, checamos o tipo MIME
do carregamento. O tipo MIME text/uri-list é usado para armazenar uma lista de identificadores recursos
uniformes (URIs), os quais podem ser nomes de arquivos, URLs (como caminhos HTTP ou FTP), ou outros
identificadores de recursos globais. Tipos padrão MIME são definidos pela Autoridade de Números Atribuídos da
Internet (IANA). Eles consistem de um tipo e subtipo separados por uma barra. A área de transferência e o sistema
de carregar e soltar usam tipos MIME para identificar diferentes tipos de data. A lista oficial de tipos MIME está
disponível em http://www.iana.org/assignments/media-types/.
void MainWindow::dropEvent(QDropEvent *event)
{
QList<QUrl> urls = event->mimeData()->urls();
if(urls.isEmpty())
return;
QString filename = urls.first().toLocalFile();
if(filename.isEmpty())
return;
if(readFile(fileName))
setWindowTitle(tr(“%1 - %2”).arg(fileName)
.arg(tr(“Drag File”)));
}
O dropEvent() é chamado quando o usuário solta um objeto no widget. Chamamos
QMimeData::urls() para obter uma lista de QUrls. Tipicamente, usuários arrastam apenas um arquivo de
cada vez, mas é possível arrastar múltiplos arquivos, arrastando uma seleção. Se há mais de uma URL, ou se a URL
não é um nome de arquivo local, retornamos imediatamente.
QWidget também fornece dragMoveEvent() e dragLeaveEvent(), mas para a maioria das
aplicações eles não precisam ser reimplementados.
O segundo exemplo ilustra como iniciar um drag e aceitar um drop. Vamos criar uma subclasse QListWidget
que suporta carregar e soltar, e usá-la como um componente na aplicação Project Chooser mostrada na figura 9.1.
Figura 9.1. A Aplicação Project Chooser
A Aplicação Project Chooser apresenta ao usuário dois widgets lista, populados com nomes. Cada widget lista
representa um objeto. O usuário pode arrastar e soltar os nomes nos widgets para mover uma pessoa de um projeto
para outro.
Todo o código de carregar e soltar está localizado na subclasse QListWidget. Aqui está a definição da classe:
Class ProjectListWidget : public QListWidget
{
Q_OBJECT;
public:
ProjectListWidget(QWidget *parente = 0);
protected:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent (QMouseEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
private:
void performDrag();
QPoint startPos;
};
A classe ProjectListWidget reimplementa cinco controladores de eventos declarados em QWidget.
ProjectListWidget::ProjectListWidget(QWidget *parent)
: QListWidget(parent)
{
setAcceptDrops(true);
}
No construtor, habilitamos ação de soltar no widget de lista.
Void ProjectListWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
startPos = event->pos();
QListWidget::mousePressEvent(event);
}
Quando o usuário pressiona o botão esquerdo do mouse, armazenamos a posição do mouse na variável privada
startPos. Chamamos a implementação QlistWidget de mousePressEvent() para assegurar que
QListWidget tem a oportunidade de processas eventos de clique como usualmente.
void ProjectListWidget::mouseMoveEvent(QMouseEvent *event)
{
if(event->buttons() & Qt::LeftButton) {
int distance = (event->pos() - startPos).manhattanLength();
if(distance >= QApplication::startDragDistance())
performDrag();
}
QListWidget::mouseMoveEvent(event);
}
Quando o usuário move o cursor enquanto segura o botão esquerdo do mouse, consideramos o início de um drag.
Computamos a distância entre a posição atual do mouse e a posição onde o botão esquerdo foi pressionado-a
“Manhattan length” é uma aproximação para cálculo rápido do tamanho de um vetor partindo de sua origem. Se a
distância é maior ou igual a distância inicial de arrastamento recomendada pela QApplication (normalmente
quatro pixels), podemos chamar a função privada performDrag() para começar a arrastar. Isto evita iniciar um
drag graças ao movimento da mão do usuário.
void ProjectListWidget::performDrag()
{
QListWidgetItem *item = currentItem();
if (item) {
QMimeData *mimeData = new QMimeData;
mimeData->setText(item->text());
QDrag *drag = new QDrag(this);
drag->setMimeData(mimeData);
drag->setPixmap(QPixmap(“:/images/person.png”));
if (drag->exec(Qt::MoveAction) == Qt::MoveAction)
delete item;
}
}
Em performDrag(), criamos um objeto do tipo QDrag e setamos this como seu pai. O objeto QDrag
armazena os dados em um objeto QMimeData. Para este exemplo, fornecemos os dados no formato string
text/plain usando QMimeData::setText(). QMimeData fornece várias funções para controle da
maioria dos tipos de itens (imagens, URLs, cores, etc) e podem controlar tipos MIME arbitrários representados como
QByteArrays. A chamada para QDrag::setPixmap() seta o ícone que segue o cursor enquanto o objeto
é arrastado.
A chamada QDrag::exec() inicia a operação de arrastamento e bloqueia até o momento em que o usuário
solta a carga arrastada ou cancela o drag. Ela faz uma combinação de chamadas “ações de arrastamento” como
argumento (Qt::CopyAction, Qt::MoveAction, e Qt::LinkAction) e retorna a ação de
arrastamento que foi executada (ou Qt::IgnoreAction caso nada tenha sido executado). Qual ação é
executada depende do que o widget fonte permite, o que o alvo suporta, e quais teclas modificadoras são
pressionadas quando o item é solto. Depois da chamada a exec(), Qt toma posse do objeto carregado e o deleta
quando ele não é mais necessário.
void ProjectListWidget::dragEnterEvent (QDragEnterEvent *event)
{
ProjectListWidget *source =
qobject_cast<ProjectListWidget *>(event->source());
if (source && source != this) {
event->setDropAction(Qt::MoveAction);
event->accept();
}
}
O widget ProjectListWidget não apenas origina arrastamentos, mas também aceita tais arrastamentos
caso eles venham de outro ProjectListWidget na mesma aplicação.
QDragEnterEvent::source() retorna um ponteiro para o widget que iniciou o arrastamento se o widget
for parte da mesma aplicação; caso contrário, retorna um ponteiro nulo. Podemos usar qobject_cast<T>()
para assegurar que o arrastamento vem de um ProjectListWidget. Se tudo estiver correto, dizemos ao Qt
que estamos prontos para aceitar a ação como uma ação de movimento.
void ProjectListWidget::dragMoveEvent(QDragMoveEvent *event)
{
ProjectListWidget *source =
qobject_cast<ProjectListWidget *>(event->source());
if(source && source != this) {
event->setDropAction (Qt::MoveAction);
event->accept();
}
}
O código em dragMoveEvent() é idêntico ao que fizemos em dragEnterEvent(). É necessário porque
precisamos sobrepor a implementação de QListWidget (na verdade, de QAbstractItemView ) da
função.
void ProjectListWidget::dropEvent(QDropEvent *event)
{
ProjectListWidget *source =
qobject_cast<ProjectListWidget *>(event->source());
if(source && source != this){
addItem(event->mimeData()->text());
event->setDropAction(Qt::MoveAction);
event->accept();
}
}
Em dropEvent(), obtemos o texto arrastado usando QMimeData::text() e criamos um item com esse
texto. Também precisamos aceitar o evento como um “evento de movimentação” para dizer ao widget fonte que ele
pode agora remover a versão original do item arrastado.
Drag and Drop é um mecanismo poderoso para transferência de dados entre aplicações. Mas em alguns casos, é
possível implementar arrastar e soltar sem usar as facilidades de Qt. Se tudo que queremos fazer é mover dados
dentro de um widget em uma aplicação, podemos simplesmente reimplementar mousePressEvent() e
mouseReleaseEvent().
Suporte a Tipos Customizados de Arrastamento
Nos exemplos até agora, confiamos no suporte de QMimeData para tipos MIME comuns. Além disso, chamamos
QMimeData::setText() para criar um arrastamento de texto, e usamos QMimeData::urls() para
recuperar o conteúdo de um arrastamento text/uri-list. Se quisermos arrastar texto simples, texto HTML,
imagens, URLs ou cores, podemos usar QMimeData sem formalidades. Mas se quisermos arrastar dados
customizados, devemos escolher uma entre as alternativas:
1. Podemos providenciar dados arbitrários como um QByteArray usando
QMimeData::setData() e os extrair mais tarde usando QMimeData::data().
2. Podemos criar uma subclasse de QMimeData e reimplementar formats() e retrieveData()
para controlar nossos tipos customizados de dados.
3. Para operações de arrastar e soltar dentro de uma aplicação, podemos criar uma subclasse QMimeData
e armazenar os dados usando qualquer estrutura de dados que quisermos.
A primeira opção não envolve uso de subclasse, mas possui alguns problemas: Precisamos converter nossa estrutura
de dados para um QByteArray mesmo se o arrastamento não é aceito por último, e se quisermos fornecer
diversos tipos MIME para interagir de uma forma legal com uma grande porção de aplicações, precisamos
armazenar os dados diversas vezes (uma vez para cada tipo MIME). Se os dados forem pesados, isso pode
desacelerar a aplicação desnecessariamente. As segunda e terceira opções podem evitar ou minimizar esses
problemas. Elas nos dão total controle e podem ser usadas em conjunto.
Para mostrar como essas alternativas funcionam, mostraremos como adicionar propriedades de arrastar e soltar em
um QTableWidget. O arrastamento vai fornecer os seguintes tipos de suportes MIME: text/plain,
text/html, e text/csv. Usando a primeira alternativa, iniciar um arrastamento parece assim:
Código:
void MyTableWidget::mouseMoveEvent (QMouseEvent *event)
{
if(event->buttons() & Qt::LeftButton) {
int distance = (event->pos() - startPos).manhattanLength();
if (distance >= QApplication::startDragDistance())
performDrag();
}
QTableWidget::mouseMoveEvent(event);
}
void MyTableWidget::performDrag()
{
QString plaintext = selectionAsPlainText();
if(plaintext.isEmpty())
return;
QMimeData *mimeData = new QMimeData;
mimeData->setText(plainText);
mimeData->setHtml(toHtml(plainText));
mimeData->setData(“text/csv”, toCsv(plainText).toUtf8());
QDrag *drag = new QDrag(this);
drag->setMimeData(mimeData);
if (drag->exec(Qt::CopyAction|Qt::MoceAction)==Qt: :MoveAction)
deleteSelection();
}
A função private performDrag() é chamada de mouseMoveEvent() para iniciar o arrastamento de uma
seleção retangular. Setamos os tipos MIME text/plain e text/html usando setText() e
setHtml(), e setamos o tipo text/csv usando setData(), que toma um tipo MIME arbitrário e um
QByteArray. O código para selectionAsString() é mais ou menos o mesmo de
Spreadsheet::copy() visto no Capítulo 4.
QString MyTableWidget::toCsv(const QString &plainText)
{
Qstring result = plaintext;
result.replace(“”, “”);
result.replace(“”, “””);
result.replace(“t”, “”””);
result.replace(“n”, “”n””);
result.prepend(“””);
result.append(“””);
return result;
}
QString MyTableWidget::toHtml (const QString &plainText)
{
QString result = Qt::escape(plainText);
result.replace(“t”, “<td>”);
result.replace(“n”,”n<tr><td>”);
result.prepend(“<table>n<tr><td>”);
result.append(“n</table>”);
return result;
}
As funções toCsv() e toHtml() convertem uma string “tabs e novas linhas” para um CSV (valores separados
por vírgula) ou um string HTML. Por exemplo, os dados
Red Green Blue
Cyan Yellow Magenta
são convertidos para
“Red”, “Green”, “Blue”
“Cyan”, “Yellow”, “Magenta”
ou para
<table>
<tr><td>Red<td>Green<Blue>
<tr><td>Cyan<td>Yellow<td>Magenta
</table>
A conversão é feita da maneira mais simples possível, usando QString::replace(). Para exibir caracteres
HTML especiais, podemos usar Qt::escape().
void MyTableWidget::dropEvent(QDropEvent *event)
{
if(event->mimeData()->hasFormat(“text/csv”)) {
QByteArray csvData = event->mimeData()->data(“text/csv”);
QString csvText = QString::fromUtf8(csvData);
…
event->acceptProposedAction();
} else if(event->mimeData()->hasFormat(“text/plain”)) {
QString plaintext = event->mimeData()->text();
…
event->acceptProposedAction();
}
}
Embora providenciemos os dados em três formas diferentes, apenas duas delas são aceitas em dropEvent().
Se o usuário arrasta células de uma QTableWidget para um editor HTML, queremos que as células sejam
convertidas em uma tabela HTML. Mas se o usuário arrasta HTML arbitrário para uma QWidgetTable, não
queremos aceitar.
Para fazer este exemplo funcionar, também precisamos chamar setAcceptDrops(true) e
setSelectionMode(ConsiguousSelection) no construtor MyTableWidget.
Refaçamos agora o exemplo, mas desta vez instanciar a subclasse de QMimeData para postergar ou evitar as
(possivelmente caras) conversões entre QTableWiidgetItems e QByteArray. Aqui está a definição da
nossa subclasse:
class TableMimeData : public QMimeData
{
Q_OBJECT
public:
TableMimeData(const QTableWidget *tableWidget,
Const QTableWidgetSelectionRange *range);
const QTableWidget *tableWidget() const {return myTableWidget; }
QTableWidgetSelectionRange range() const { return myRange; }
QStringList formats() const;
protected:
QVariant retrieveData(const QString &format,
QVariant::Type preferredType) const;
private:
static QString toHtml(const QString &plainText);
static QString toCsv(const QString &plainText);
QString text(int row, int column) const;
QString rangeAsPlainText() const;
Const QTableWidget *myTableWidget;
QTableWIdgetSelectionRange myRange;
QStringList myFormat;
};
Ao invés de armazenas os dados reais, armazenamos um QTableWidgetSelectionRange que especifica
quais células estão sendo arrastadas e mantemos um ponteiro para QTableWidget. As funções formats()
e retrieveData() são reimplementadas de QMimeData.
TableMimeData::TableMimeData(const QTableWidget *tableWidget,
Const QTableWidgetSelectionRange &range)
{
myTableWidget = tableWidget;
myRange = range;
myFormats << ‘text/csv” << “text/html” << “text/plain”;
}
No construtor, inicializamos as variáveis privadas.
QStringList TableMimeData::formats() const
{
Return myFormats;
}
A função formats() retorna uma lista de tipos MIME fornecidos pelo objeto de dados MIME. A ordem precisa
dos formatos é geralmente irrelevante, mas é uma boa prática colocar os “melhores” formatos primeiro. Aplicações
que suportam muitos formatos usarão algumas vezes o primeiro formato que for compatível.
QStringList TableMimeData::formats()
{
Return myFormats;
}
A função retrieveData() retorna os dados para um dado tipo MIME na forma de QVariant. O valor do
parâmetro de format é normalmente uma das strings retornadas por formats(), mas não podemos assumir
que, já que nem todas as aplicações checam o tipo MIME frente a formats(). As funções text(), html(),
urls(), imageData(), colorData(), e data() fornecidas por QMimeData são implementadas em
termos de retrieveData().
O parâmetro preferredType nos dá uma dica sobre qual tipo devemos inserir na QVariant. Aqui,
ignoramos isto e confiamos a QMimeData a tarefa de converter o valor de retorno no tipo desejado, se for
necessário.
void MyTableWidget::dropEvent(QDropEvent *event)
{
const TableMimeData *tableData =
qobject_cast<const TableMimeData *>(event->mimeData());
if(tableData){
const QTableWidget *otherTable = tableData->tableWidget();
QTableWidgetSelectionRange ptherRange = tableData->range();
…
event->acceptProposedAction();
} else if (event->mimeData()->hasFormat(“text/csv”)) {
QByteArray csvData = event->mimeData()->data(“text/csv”);
QString csvText = QString::fromUtf8(csvData);
…
event->acceptProposedAction();
} else if (event->mimeData()->hasFormat(“text/plain”)) {
QString plaintext = event->mimeData()->text();
…
event->acceptProposedAction();
}
QTableWidget::mouseMoveEvent(event);
}
A função dropEvent() é parecida com a que tivemos mais cedo nesta sessão, mas desta vez a otimizamos,
verificando se podemos converter com segurança o objeto QMimeData em um TableMimeData. Se
qobject_cast<T>() funcionar, significa que o arrastamento foi originado de um MyTableWidget na
mesma aplicação, e podemos diretamente acessar os dados da tabela ao invés de ir através da API de
QMimeData. Se a conversão falhar, extraímos os dados na maneira padrão.
Neste exemplo, codificamos o texto CSV usando a formatação UTF-8. Se quisermos ter certeza de estar usando a
formatação correta, poderíamos usar o parâmetro charset do tipo MIME text/plain para especificar uma formatação
explícita. Aqui estão alguns exemplos:
text/plain;charset=US-ASCII
text/plain;charset=ISSO-8859-1
text/plain;charset=Shift_JIS
text/plain;charset=UTF-8
Controle a Área de Transferência
A maioria das aplicações faz uso do controle de transferência pré-construído do Qt de uma forma ou de outra. Por
exemplo, a classe QTextEdit fornece opções de cut(), copy() e paste() bem como atalhos de teclado,
assim pouco ou nenhum código adicional é necessário.
Ao escrever nossas próprias classes, podemos acessar a Área de Transferência através de
QApplication::clipboard(), que retorna um ponteiro para o objeto QClipboard da aplicação.
Controlar a área de transferência do sistema é fácil: faça uma chamada a setText(), setImage(), ou
setPixmap() para inserir dados na área de transferência, e chame text(), image() ou pixmap() para
recuperar dados da área de transferência. Já vimos exemplos de uso da área de transferência na aplicação
Spreadsheet do Capítulo 4.
Para algumas aplicações, a funcionalidade construída pode não ser suficiente. Por exemplo, pode ser que
queiramos fornecer que não é apenas texto ou imagem, ou podemos vir a querer fornecer dados em diversos
formatos para máxima interoperabilidade com outras aplicações. Este caso é muito similar com o que encontramos
mais cedo em arrastar e soltar, e a resposta também é similar: Podemos chamar uma subclasse de QMimeData e
reimplementar alguns funções virtuais.
Caso nossa aplicação suporte drag and drop através de uma subclasse customizada QMimeData, podemos
simplesmente reusar a subclasse QMimeData e a colocar na área de transferência usando a função
setMimeData(). Para recuperar os dados, podemos chamar mimeData() na área de transferência.
Em X11, geralmente é possível colar uma seleção clicando no botão do meio de um mouse de três botões. Isto é
feito usando uma área de transferência “de seleção” separada. Se quiser que seus widgets forneçam este tipo de
área de transferência assim como a padrão, você deve passar QClipboard::Selection como um
argumento adicional para as várias chamadas chamas de área de transferência. Por exemplo, aqui vemos como
reimplementaríamos mouseReleaseEvent() em um editor de texto para fornecer suporte a ação de colar
usando o botão do meio do mouse:
void MyTextEditor::mouseReleaseEvent(QMouseEvent *event)
{
QClipboard *clipboard = QApplication::clipboard();
if (event->button() == Qt::MidButton
&& clipboard->supportsSelection() {
QString text = clipboard->text(QClipboard::Selection);
pasteText(text);
}
}
Em X11, a função supportsSelection() retorna true. Em outras plataformas, retorna false.
Se quisermos ser notificados sempre que o conteúdo da área de transferência muda, podemos conectar o sinal
QClipboard::dataChanged() a uma opção customizada.

Mais conteúdo relacionado

Semelhante a Drag and Drop no Qt - Habilitando arrastar e soltar e controlando formatos customizados

Aula 15 e 16 - Navegação - Activities e Fragments.pptx.pdf
Aula 15 e 16 - Navegação - Activities e Fragments.pptx.pdfAula 15 e 16 - Navegação - Activities e Fragments.pptx.pdf
Aula 15 e 16 - Navegação - Activities e Fragments.pptx.pdfnosbisantos
 
Introdução a programação em Android
Introdução a programação em AndroidIntrodução a programação em Android
Introdução a programação em AndroidPedro Veloso
 
Construindo sua primeira aplicação android
Construindo sua primeira aplicação androidConstruindo sua primeira aplicação android
Construindo sua primeira aplicação android666Insanity
 
Desmistificando o cairngorm
Desmistificando o cairngormDesmistificando o cairngorm
Desmistificando o cairngormEric Cavalcanti
 
Introdução ao Android (minicurso 4h)
Introdução ao Android (minicurso 4h)Introdução ao Android (minicurso 4h)
Introdução ao Android (minicurso 4h)Rodrigo Rocha
 
TDC 2015 - Execução em Background e Live Tiles em Universal Apps
TDC 2015 - Execução em Background e Live Tiles em Universal AppsTDC 2015 - Execução em Background e Live Tiles em Universal Apps
TDC 2015 - Execução em Background e Live Tiles em Universal AppsDiego Castro
 
Curso Android - 03 Conceitos Chaves
Curso Android - 03 Conceitos ChavesCurso Android - 03 Conceitos Chaves
Curso Android - 03 Conceitos ChavesRonildo Oliveira
 
Testes em Aplicações Web com Cactus
Testes em Aplicações Web com CactusTestes em Aplicações Web com Cactus
Testes em Aplicações Web com CactusDenis L Presciliano
 
Desenvolvimento de Apps e Games para Android - Parte 7
Desenvolvimento de Apps e Games para Android - Parte 7Desenvolvimento de Apps e Games para Android - Parte 7
Desenvolvimento de Apps e Games para Android - Parte 7Erisvaldo Junior
 
Desenvolvimento de Apps e Games para Android - Partes 6 e 7 (Preview)
Desenvolvimento de Apps e Games para Android - Partes 6 e 7 (Preview)Desenvolvimento de Apps e Games para Android - Partes 6 e 7 (Preview)
Desenvolvimento de Apps e Games para Android - Partes 6 e 7 (Preview)Erisvaldo Junior
 
Apostila:Curso de java II
Apostila:Curso de java II  Apostila:Curso de java II
Apostila:Curso de java II Verônica Veiga
 
Evento Front End SP - Organizando o Javascript
 Evento Front End SP - Organizando o Javascript Evento Front End SP - Organizando o Javascript
Evento Front End SP - Organizando o JavascriptMichel Ribeiro
 

Semelhante a Drag and Drop no Qt - Habilitando arrastar e soltar e controlando formatos customizados (20)

Cap12
Cap12Cap12
Cap12
 
Aula 15 e 16 - Navegação - Activities e Fragments.pptx.pdf
Aula 15 e 16 - Navegação - Activities e Fragments.pptx.pdfAula 15 e 16 - Navegação - Activities e Fragments.pptx.pdf
Aula 15 e 16 - Navegação - Activities e Fragments.pptx.pdf
 
Introdução a programação em Android
Introdução a programação em AndroidIntrodução a programação em Android
Introdução a programação em Android
 
Construindo sua primeira aplicação android
Construindo sua primeira aplicação androidConstruindo sua primeira aplicação android
Construindo sua primeira aplicação android
 
Android Para Iniciantes
Android Para IniciantesAndroid Para Iniciantes
Android Para Iniciantes
 
Desmistificando o cairngorm
Desmistificando o cairngormDesmistificando o cairngorm
Desmistificando o cairngorm
 
Introdução ao Android (minicurso 4h)
Introdução ao Android (minicurso 4h)Introdução ao Android (minicurso 4h)
Introdução ao Android (minicurso 4h)
 
TDC 2015 - Execução em Background e Live Tiles em Universal Apps
TDC 2015 - Execução em Background e Live Tiles em Universal AppsTDC 2015 - Execução em Background e Live Tiles em Universal Apps
TDC 2015 - Execução em Background e Live Tiles em Universal Apps
 
Curso Android - 03 Conceitos Chaves
Curso Android - 03 Conceitos ChavesCurso Android - 03 Conceitos Chaves
Curso Android - 03 Conceitos Chaves
 
CURSO JAVA 02
CURSO JAVA 02CURSO JAVA 02
CURSO JAVA 02
 
Introdução a jQuery
Introdução a jQueryIntrodução a jQuery
Introdução a jQuery
 
Testes em Aplicações Web com Cactus
Testes em Aplicações Web com CactusTestes em Aplicações Web com Cactus
Testes em Aplicações Web com Cactus
 
Fragmentos
FragmentosFragmentos
Fragmentos
 
Android na Prática
Android na PráticaAndroid na Prática
Android na Prática
 
Desenvolvimento de Apps e Games para Android - Parte 7
Desenvolvimento de Apps e Games para Android - Parte 7Desenvolvimento de Apps e Games para Android - Parte 7
Desenvolvimento de Apps e Games para Android - Parte 7
 
Android wear
Android wearAndroid wear
Android wear
 
Desenvolvimento de Apps e Games para Android - Partes 6 e 7 (Preview)
Desenvolvimento de Apps e Games para Android - Partes 6 e 7 (Preview)Desenvolvimento de Apps e Games para Android - Partes 6 e 7 (Preview)
Desenvolvimento de Apps e Games para Android - Partes 6 e 7 (Preview)
 
Apostila:Curso de java II
Apostila:Curso de java II  Apostila:Curso de java II
Apostila:Curso de java II
 
Mock Objects
Mock ObjectsMock Objects
Mock Objects
 
Evento Front End SP - Organizando o Javascript
 Evento Front End SP - Organizando o Javascript Evento Front End SP - Organizando o Javascript
Evento Front End SP - Organizando o Javascript
 

Mais de Cedemir Pereira

Mais de Cedemir Pereira (6)

cdr-intro.pdf
cdr-intro.pdfcdr-intro.pdf
cdr-intro.pdf
 
Livro Cidades Inteligentes(2)-31-66.pdf
Livro Cidades Inteligentes(2)-31-66.pdfLivro Cidades Inteligentes(2)-31-66.pdf
Livro Cidades Inteligentes(2)-31-66.pdf
 
slidesWtisc(1).pptx
slidesWtisc(1).pptxslidesWtisc(1).pptx
slidesWtisc(1).pptx
 
Cap11
Cap11Cap11
Cap11
 
Cap7
Cap7Cap7
Cap7
 
Cap6
Cap6Cap6
Cap6
 

Drag and Drop no Qt - Habilitando arrastar e soltar e controlando formatos customizados

  • 1. 9 . Arrastar e Soltar  Habilitando Arrastar e Soltar  Suporte a tipos Customizados de Arrastamento  Controlando a Área de Transferência “Drag and Drop”, ou Arrastar e soltar é uma forma moderna e intuitiva de transferir informação em uma aplicação ou entre aplicações diferentes. È geralmente fornecida em adição ao suporte a clipboard para mover e copiar dados. Neste capítulo, veremos como adicionar suporte a arrastar e soltar a uma aplicação e como controlar formatos customizados. Então mostraremos como reusar o código do arrastar e soltar para adicionar suporte ao clipboard. Esta reutilização de código é possível porque ambos mecanismos são baseados em QMimeData, uma classe que pode fornecer dados em diversos formatos. Habilitando Arrastar e Soltar Drag e Drop envolve duas ações distintas: Arrastar e soltar algo. Widgets do Qt podem servir como pontos de arrastamento, ou como pontos de soltura, ou como ambos. Nosso primeiro exemplo mostra como fazer uma aplicação Qt aceitar um arrastamento iniciado por outra aplicação. A aplicação Qt é uma janela principal como um QTextEdit como seu widget central. Quando o usuário carrega um arquivo texto da Área de Trabalho ou por um explorador de arquivos e o solta na aplicação, a aplicação carrega o arquivo dentro de QTextEdit. Aqui está a definição da classe MainWindow do exemplo: Class MainWindow : public QMainWindow { Q_OBJECT; public: MainWindow(); protected: void dragEnterEvent(QDragEnterEvent *event); void dropEvent(QDropEvent *event);
  • 2. private: bool readFile(const QString &fileName); QTextEdit *textEdit; }; A classe MainWindow reimplementa dragEnterEvemt() e dropEvent() de QWidget. Já que o propósito desse exemplo é mostrar a funcionalidade arrastar e soltar, a maioria da funcionalidade que esperaríamos ver em uma classe de janela principal foi omitida. MainWindow::MainWindow() { textEdit = new QTextEdit; setCentralWidget (textEdit); textEdit->setAcceptDrops(false); setAcceptDrops(true); setWindowTitle(tr(“Text Editor”)); } No construtor, criamos um QTextEdit e o setamos como o widget central. Por padrão, QTextEdit aceita arrastes textuais de outras aplicações, e se o usuário solta um arquivo dentro dele, o nome do arquivo será inserido no texto. Já que eventos de drop são propagados do filho para o pai, desabilitando a funcionalidade de soltar no QTextEdit e a habilitando na janela principal obtemos os eventos de drop para a janela inteira em MainWindow. void MainWindow::dragEnterEvent (QDragEnterEvent *event) { if(event->mimeData()->hasFormat(“text/uri-list”)) event->acceptProposedAction(); } O dragEnterEvent()é chamado a qualquer momento em que o usuário arrasta um objeto para dentro do widget. Se chamarmos acceptProposedAction() no evento, indicamos que o usuário pode soltar o objeto carregado no widget. Por padrão, o widget não aceitaria o objeto. Qt automaticamente muda o cursor para indicar ao usuário quando o widget é considerado um ponto de soltura. Aqui queremos que o usuário seja autorizado a carregar arquivos, mas nada mais. Para tal, checamos o tipo MIME do carregamento. O tipo MIME text/uri-list é usado para armazenar uma lista de identificadores recursos uniformes (URIs), os quais podem ser nomes de arquivos, URLs (como caminhos HTTP ou FTP), ou outros identificadores de recursos globais. Tipos padrão MIME são definidos pela Autoridade de Números Atribuídos da Internet (IANA). Eles consistem de um tipo e subtipo separados por uma barra. A área de transferência e o sistema de carregar e soltar usam tipos MIME para identificar diferentes tipos de data. A lista oficial de tipos MIME está disponível em http://www.iana.org/assignments/media-types/. void MainWindow::dropEvent(QDropEvent *event) { QList<QUrl> urls = event->mimeData()->urls(); if(urls.isEmpty()) return; QString filename = urls.first().toLocalFile(); if(filename.isEmpty()) return; if(readFile(fileName)) setWindowTitle(tr(“%1 - %2”).arg(fileName) .arg(tr(“Drag File”))); }
  • 3. O dropEvent() é chamado quando o usuário solta um objeto no widget. Chamamos QMimeData::urls() para obter uma lista de QUrls. Tipicamente, usuários arrastam apenas um arquivo de cada vez, mas é possível arrastar múltiplos arquivos, arrastando uma seleção. Se há mais de uma URL, ou se a URL não é um nome de arquivo local, retornamos imediatamente. QWidget também fornece dragMoveEvent() e dragLeaveEvent(), mas para a maioria das aplicações eles não precisam ser reimplementados. O segundo exemplo ilustra como iniciar um drag e aceitar um drop. Vamos criar uma subclasse QListWidget que suporta carregar e soltar, e usá-la como um componente na aplicação Project Chooser mostrada na figura 9.1. Figura 9.1. A Aplicação Project Chooser A Aplicação Project Chooser apresenta ao usuário dois widgets lista, populados com nomes. Cada widget lista representa um objeto. O usuário pode arrastar e soltar os nomes nos widgets para mover uma pessoa de um projeto para outro. Todo o código de carregar e soltar está localizado na subclasse QListWidget. Aqui está a definição da classe: Class ProjectListWidget : public QListWidget { Q_OBJECT; public: ProjectListWidget(QWidget *parente = 0); protected: void mousePressEvent(QMouseEvent *event); void mouseMoveEvent (QMouseEvent *event); void dragEnterEvent(QDragEnterEvent *event); void dragMoveEvent(QDragMoveEvent *event); void dropEvent(QDropEvent *event); private: void performDrag(); QPoint startPos; }; A classe ProjectListWidget reimplementa cinco controladores de eventos declarados em QWidget.
  • 4. ProjectListWidget::ProjectListWidget(QWidget *parent) : QListWidget(parent) { setAcceptDrops(true); } No construtor, habilitamos ação de soltar no widget de lista. Void ProjectListWidget::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) startPos = event->pos(); QListWidget::mousePressEvent(event); } Quando o usuário pressiona o botão esquerdo do mouse, armazenamos a posição do mouse na variável privada startPos. Chamamos a implementação QlistWidget de mousePressEvent() para assegurar que QListWidget tem a oportunidade de processas eventos de clique como usualmente. void ProjectListWidget::mouseMoveEvent(QMouseEvent *event) { if(event->buttons() & Qt::LeftButton) { int distance = (event->pos() - startPos).manhattanLength(); if(distance >= QApplication::startDragDistance()) performDrag(); } QListWidget::mouseMoveEvent(event); } Quando o usuário move o cursor enquanto segura o botão esquerdo do mouse, consideramos o início de um drag. Computamos a distância entre a posição atual do mouse e a posição onde o botão esquerdo foi pressionado-a “Manhattan length” é uma aproximação para cálculo rápido do tamanho de um vetor partindo de sua origem. Se a distância é maior ou igual a distância inicial de arrastamento recomendada pela QApplication (normalmente quatro pixels), podemos chamar a função privada performDrag() para começar a arrastar. Isto evita iniciar um drag graças ao movimento da mão do usuário. void ProjectListWidget::performDrag() { QListWidgetItem *item = currentItem(); if (item) { QMimeData *mimeData = new QMimeData; mimeData->setText(item->text()); QDrag *drag = new QDrag(this); drag->setMimeData(mimeData); drag->setPixmap(QPixmap(“:/images/person.png”)); if (drag->exec(Qt::MoveAction) == Qt::MoveAction) delete item; } } Em performDrag(), criamos um objeto do tipo QDrag e setamos this como seu pai. O objeto QDrag armazena os dados em um objeto QMimeData. Para este exemplo, fornecemos os dados no formato string text/plain usando QMimeData::setText(). QMimeData fornece várias funções para controle da maioria dos tipos de itens (imagens, URLs, cores, etc) e podem controlar tipos MIME arbitrários representados como QByteArrays. A chamada para QDrag::setPixmap() seta o ícone que segue o cursor enquanto o objeto é arrastado. A chamada QDrag::exec() inicia a operação de arrastamento e bloqueia até o momento em que o usuário solta a carga arrastada ou cancela o drag. Ela faz uma combinação de chamadas “ações de arrastamento” como argumento (Qt::CopyAction, Qt::MoveAction, e Qt::LinkAction) e retorna a ação de
  • 5. arrastamento que foi executada (ou Qt::IgnoreAction caso nada tenha sido executado). Qual ação é executada depende do que o widget fonte permite, o que o alvo suporta, e quais teclas modificadoras são pressionadas quando o item é solto. Depois da chamada a exec(), Qt toma posse do objeto carregado e o deleta quando ele não é mais necessário. void ProjectListWidget::dragEnterEvent (QDragEnterEvent *event) { ProjectListWidget *source = qobject_cast<ProjectListWidget *>(event->source()); if (source && source != this) { event->setDropAction(Qt::MoveAction); event->accept(); } } O widget ProjectListWidget não apenas origina arrastamentos, mas também aceita tais arrastamentos caso eles venham de outro ProjectListWidget na mesma aplicação. QDragEnterEvent::source() retorna um ponteiro para o widget que iniciou o arrastamento se o widget for parte da mesma aplicação; caso contrário, retorna um ponteiro nulo. Podemos usar qobject_cast<T>() para assegurar que o arrastamento vem de um ProjectListWidget. Se tudo estiver correto, dizemos ao Qt que estamos prontos para aceitar a ação como uma ação de movimento. void ProjectListWidget::dragMoveEvent(QDragMoveEvent *event) { ProjectListWidget *source = qobject_cast<ProjectListWidget *>(event->source()); if(source && source != this) { event->setDropAction (Qt::MoveAction); event->accept(); } } O código em dragMoveEvent() é idêntico ao que fizemos em dragEnterEvent(). É necessário porque precisamos sobrepor a implementação de QListWidget (na verdade, de QAbstractItemView ) da função. void ProjectListWidget::dropEvent(QDropEvent *event) { ProjectListWidget *source = qobject_cast<ProjectListWidget *>(event->source()); if(source && source != this){ addItem(event->mimeData()->text()); event->setDropAction(Qt::MoveAction); event->accept(); } } Em dropEvent(), obtemos o texto arrastado usando QMimeData::text() e criamos um item com esse texto. Também precisamos aceitar o evento como um “evento de movimentação” para dizer ao widget fonte que ele pode agora remover a versão original do item arrastado. Drag and Drop é um mecanismo poderoso para transferência de dados entre aplicações. Mas em alguns casos, é possível implementar arrastar e soltar sem usar as facilidades de Qt. Se tudo que queremos fazer é mover dados dentro de um widget em uma aplicação, podemos simplesmente reimplementar mousePressEvent() e mouseReleaseEvent(). Suporte a Tipos Customizados de Arrastamento
  • 6. Nos exemplos até agora, confiamos no suporte de QMimeData para tipos MIME comuns. Além disso, chamamos QMimeData::setText() para criar um arrastamento de texto, e usamos QMimeData::urls() para recuperar o conteúdo de um arrastamento text/uri-list. Se quisermos arrastar texto simples, texto HTML, imagens, URLs ou cores, podemos usar QMimeData sem formalidades. Mas se quisermos arrastar dados customizados, devemos escolher uma entre as alternativas: 1. Podemos providenciar dados arbitrários como um QByteArray usando QMimeData::setData() e os extrair mais tarde usando QMimeData::data(). 2. Podemos criar uma subclasse de QMimeData e reimplementar formats() e retrieveData() para controlar nossos tipos customizados de dados. 3. Para operações de arrastar e soltar dentro de uma aplicação, podemos criar uma subclasse QMimeData e armazenar os dados usando qualquer estrutura de dados que quisermos. A primeira opção não envolve uso de subclasse, mas possui alguns problemas: Precisamos converter nossa estrutura de dados para um QByteArray mesmo se o arrastamento não é aceito por último, e se quisermos fornecer diversos tipos MIME para interagir de uma forma legal com uma grande porção de aplicações, precisamos armazenar os dados diversas vezes (uma vez para cada tipo MIME). Se os dados forem pesados, isso pode desacelerar a aplicação desnecessariamente. As segunda e terceira opções podem evitar ou minimizar esses problemas. Elas nos dão total controle e podem ser usadas em conjunto. Para mostrar como essas alternativas funcionam, mostraremos como adicionar propriedades de arrastar e soltar em um QTableWidget. O arrastamento vai fornecer os seguintes tipos de suportes MIME: text/plain, text/html, e text/csv. Usando a primeira alternativa, iniciar um arrastamento parece assim: Código: void MyTableWidget::mouseMoveEvent (QMouseEvent *event) { if(event->buttons() & Qt::LeftButton) { int distance = (event->pos() - startPos).manhattanLength(); if (distance >= QApplication::startDragDistance()) performDrag(); } QTableWidget::mouseMoveEvent(event); } void MyTableWidget::performDrag() { QString plaintext = selectionAsPlainText(); if(plaintext.isEmpty()) return; QMimeData *mimeData = new QMimeData; mimeData->setText(plainText); mimeData->setHtml(toHtml(plainText)); mimeData->setData(“text/csv”, toCsv(plainText).toUtf8()); QDrag *drag = new QDrag(this); drag->setMimeData(mimeData); if (drag->exec(Qt::CopyAction|Qt::MoceAction)==Qt: :MoveAction) deleteSelection(); } A função private performDrag() é chamada de mouseMoveEvent() para iniciar o arrastamento de uma seleção retangular. Setamos os tipos MIME text/plain e text/html usando setText() e setHtml(), e setamos o tipo text/csv usando setData(), que toma um tipo MIME arbitrário e um QByteArray. O código para selectionAsString() é mais ou menos o mesmo de Spreadsheet::copy() visto no Capítulo 4.
  • 7. QString MyTableWidget::toCsv(const QString &plainText) { Qstring result = plaintext; result.replace(“”, “”); result.replace(“”, “””); result.replace(“t”, “”””); result.replace(“n”, “”n””); result.prepend(“””); result.append(“””); return result; } QString MyTableWidget::toHtml (const QString &plainText) { QString result = Qt::escape(plainText); result.replace(“t”, “<td>”); result.replace(“n”,”n<tr><td>”); result.prepend(“<table>n<tr><td>”); result.append(“n</table>”); return result; } As funções toCsv() e toHtml() convertem uma string “tabs e novas linhas” para um CSV (valores separados por vírgula) ou um string HTML. Por exemplo, os dados Red Green Blue Cyan Yellow Magenta são convertidos para “Red”, “Green”, “Blue” “Cyan”, “Yellow”, “Magenta” ou para <table> <tr><td>Red<td>Green<Blue> <tr><td>Cyan<td>Yellow<td>Magenta </table> A conversão é feita da maneira mais simples possível, usando QString::replace(). Para exibir caracteres HTML especiais, podemos usar Qt::escape(). void MyTableWidget::dropEvent(QDropEvent *event) { if(event->mimeData()->hasFormat(“text/csv”)) { QByteArray csvData = event->mimeData()->data(“text/csv”); QString csvText = QString::fromUtf8(csvData); … event->acceptProposedAction(); } else if(event->mimeData()->hasFormat(“text/plain”)) { QString plaintext = event->mimeData()->text(); … event->acceptProposedAction(); } } Embora providenciemos os dados em três formas diferentes, apenas duas delas são aceitas em dropEvent(). Se o usuário arrasta células de uma QTableWidget para um editor HTML, queremos que as células sejam
  • 8. convertidas em uma tabela HTML. Mas se o usuário arrasta HTML arbitrário para uma QWidgetTable, não queremos aceitar. Para fazer este exemplo funcionar, também precisamos chamar setAcceptDrops(true) e setSelectionMode(ConsiguousSelection) no construtor MyTableWidget. Refaçamos agora o exemplo, mas desta vez instanciar a subclasse de QMimeData para postergar ou evitar as (possivelmente caras) conversões entre QTableWiidgetItems e QByteArray. Aqui está a definição da nossa subclasse: class TableMimeData : public QMimeData { Q_OBJECT public: TableMimeData(const QTableWidget *tableWidget, Const QTableWidgetSelectionRange *range); const QTableWidget *tableWidget() const {return myTableWidget; } QTableWidgetSelectionRange range() const { return myRange; } QStringList formats() const; protected: QVariant retrieveData(const QString &format, QVariant::Type preferredType) const; private: static QString toHtml(const QString &plainText); static QString toCsv(const QString &plainText); QString text(int row, int column) const; QString rangeAsPlainText() const; Const QTableWidget *myTableWidget; QTableWIdgetSelectionRange myRange; QStringList myFormat; }; Ao invés de armazenas os dados reais, armazenamos um QTableWidgetSelectionRange que especifica quais células estão sendo arrastadas e mantemos um ponteiro para QTableWidget. As funções formats() e retrieveData() são reimplementadas de QMimeData. TableMimeData::TableMimeData(const QTableWidget *tableWidget, Const QTableWidgetSelectionRange &range) { myTableWidget = tableWidget; myRange = range; myFormats << ‘text/csv” << “text/html” << “text/plain”; } No construtor, inicializamos as variáveis privadas. QStringList TableMimeData::formats() const { Return myFormats; } A função formats() retorna uma lista de tipos MIME fornecidos pelo objeto de dados MIME. A ordem precisa dos formatos é geralmente irrelevante, mas é uma boa prática colocar os “melhores” formatos primeiro. Aplicações que suportam muitos formatos usarão algumas vezes o primeiro formato que for compatível.
  • 9. QStringList TableMimeData::formats() { Return myFormats; } A função retrieveData() retorna os dados para um dado tipo MIME na forma de QVariant. O valor do parâmetro de format é normalmente uma das strings retornadas por formats(), mas não podemos assumir que, já que nem todas as aplicações checam o tipo MIME frente a formats(). As funções text(), html(), urls(), imageData(), colorData(), e data() fornecidas por QMimeData são implementadas em termos de retrieveData(). O parâmetro preferredType nos dá uma dica sobre qual tipo devemos inserir na QVariant. Aqui, ignoramos isto e confiamos a QMimeData a tarefa de converter o valor de retorno no tipo desejado, se for necessário. void MyTableWidget::dropEvent(QDropEvent *event) { const TableMimeData *tableData = qobject_cast<const TableMimeData *>(event->mimeData()); if(tableData){ const QTableWidget *otherTable = tableData->tableWidget(); QTableWidgetSelectionRange ptherRange = tableData->range(); … event->acceptProposedAction(); } else if (event->mimeData()->hasFormat(“text/csv”)) { QByteArray csvData = event->mimeData()->data(“text/csv”); QString csvText = QString::fromUtf8(csvData); … event->acceptProposedAction(); } else if (event->mimeData()->hasFormat(“text/plain”)) { QString plaintext = event->mimeData()->text(); … event->acceptProposedAction(); } QTableWidget::mouseMoveEvent(event); } A função dropEvent() é parecida com a que tivemos mais cedo nesta sessão, mas desta vez a otimizamos, verificando se podemos converter com segurança o objeto QMimeData em um TableMimeData. Se qobject_cast<T>() funcionar, significa que o arrastamento foi originado de um MyTableWidget na mesma aplicação, e podemos diretamente acessar os dados da tabela ao invés de ir através da API de QMimeData. Se a conversão falhar, extraímos os dados na maneira padrão. Neste exemplo, codificamos o texto CSV usando a formatação UTF-8. Se quisermos ter certeza de estar usando a formatação correta, poderíamos usar o parâmetro charset do tipo MIME text/plain para especificar uma formatação explícita. Aqui estão alguns exemplos: text/plain;charset=US-ASCII text/plain;charset=ISSO-8859-1 text/plain;charset=Shift_JIS text/plain;charset=UTF-8 Controle a Área de Transferência A maioria das aplicações faz uso do controle de transferência pré-construído do Qt de uma forma ou de outra. Por exemplo, a classe QTextEdit fornece opções de cut(), copy() e paste() bem como atalhos de teclado, assim pouco ou nenhum código adicional é necessário.
  • 10. Ao escrever nossas próprias classes, podemos acessar a Área de Transferência através de QApplication::clipboard(), que retorna um ponteiro para o objeto QClipboard da aplicação. Controlar a área de transferência do sistema é fácil: faça uma chamada a setText(), setImage(), ou setPixmap() para inserir dados na área de transferência, e chame text(), image() ou pixmap() para recuperar dados da área de transferência. Já vimos exemplos de uso da área de transferência na aplicação Spreadsheet do Capítulo 4. Para algumas aplicações, a funcionalidade construída pode não ser suficiente. Por exemplo, pode ser que queiramos fornecer que não é apenas texto ou imagem, ou podemos vir a querer fornecer dados em diversos formatos para máxima interoperabilidade com outras aplicações. Este caso é muito similar com o que encontramos mais cedo em arrastar e soltar, e a resposta também é similar: Podemos chamar uma subclasse de QMimeData e reimplementar alguns funções virtuais. Caso nossa aplicação suporte drag and drop através de uma subclasse customizada QMimeData, podemos simplesmente reusar a subclasse QMimeData e a colocar na área de transferência usando a função setMimeData(). Para recuperar os dados, podemos chamar mimeData() na área de transferência. Em X11, geralmente é possível colar uma seleção clicando no botão do meio de um mouse de três botões. Isto é feito usando uma área de transferência “de seleção” separada. Se quiser que seus widgets forneçam este tipo de área de transferência assim como a padrão, você deve passar QClipboard::Selection como um argumento adicional para as várias chamadas chamas de área de transferência. Por exemplo, aqui vemos como reimplementaríamos mouseReleaseEvent() em um editor de texto para fornecer suporte a ação de colar usando o botão do meio do mouse: void MyTextEditor::mouseReleaseEvent(QMouseEvent *event) { QClipboard *clipboard = QApplication::clipboard(); if (event->button() == Qt::MidButton && clipboard->supportsSelection() { QString text = clipboard->text(QClipboard::Selection); pasteText(text); } } Em X11, a função supportsSelection() retorna true. Em outras plataformas, retorna false. Se quisermos ser notificados sempre que o conteúdo da área de transferência muda, podemos conectar o sinal QClipboard::dataChanged() a uma opção customizada.