Minicurso Qt - USP( Ou a construção do Caos)
Minicurso Qt - USP
Minicurso Qt - USPPorque Qt?
- C++ / Orientação a Objetos- Moc- Sinais / Slots- Genealogia- Widgets- Threads- Multimedia- XML- Banco de Dados- Animações- Multiplataforma- Leve- i18n, l10n. ( seja lá o que isso quer dizer )- Programação Concorrente- Sockets
Minicurso Qt - USP
Pré Requisitos:
Orientação a Objetos( Seja Java, Python, Ruby ou whattahell )
Vontade de aprender
Desejavel:
Conhecimentos em C++
Minicurso Qt - USPObjetivos:
He Has the technology, He can make you Better, Faster, Stronger.
- Introduzir o Qt de forma Prática
- Iniciar uma vivência em Grupo
- Discutir Relações de Projeto
- Distribuir Balinhas de Banana
Minicurso Qt - USPMétodologia:
- Aula Prática com intervenções artisticas.- Meia hora de Aula para Meia hora de
Implementação.- Xp Programming - 2 alunos por computador
Referências:- Qt Quaterly- Qt Documentation- api.kde.org- labs.trolltech.com- Qt Center
Minicurso Qt - USP
C++ ( ou o testamento da ira)
Minicurso Qt - USP
C++:Baixo nivelAlto nivelFlexivelCódigo GenéricoOrientada a ObjetosEstruturadaconst char *const a()
Minicurso Qt - USPconst não é Constante.
const é Muita coisa:
const int a = 10;
const char *const b = "waha";
int Classe::blah() const;
const int *const Classe::bleh() const;
Minicurso Qt - USP
const é 'somente leitura'
const int a = 10;
Valendo 1 bala.
Minicurso Qt - USP
const é não - modificavel.int const* a;
const é somente-leitura-não-modificavelconst char * const a = "nãomudo."
const método não pode alterar o objeto.void Classe::metodo() const;
Minicurso Qt - USP
Valores · Ponteiros · Referencias
int a; ← valorint *b; ← ponteiroint &c; ← referencia
Diferenças? ( Balinhas )
Minicurso Qt - USP
class A {public:
A(); ← ConstrutorA(const A& a); ← Balinha~A(); ← Destrutor
}; ← Sim, ponto - e - virgula.
Minicurso Qt - USP
class A{virtual void blah() = 0;virtual void bleh();bool geh() const;
};
Minicurso Qt - USP
C++ NÃO é Compativel com C.
Válido em C, Inválido em C++
void a(void){int new = 2;
}
exemplos no quadro, Valendo Balinha.
C++ NÃO é OO
Chocante, não?
- Linguagem Genérica- Caracteristicas OO- Caracteristicas Estruturada- Caracteristicas Funcionais- Caracteristicas OE
#include <cstring>#include <cstdio>
int main(){ char *letras =(char*) "salvesalvesimpatia"; if (strlen(letras) < -1){ printf("Pois é..."); } return 0;}
Brincadeira do C - Do - Mal
Brincadeira do C - Do - Mal
size_t strlen( const char* c);typedef unsigned int size_t;
-1 não é unsigned.size_t é.
Qual o problema?
Minicurso Qt - USP
Pequena História do Qt
4.0 - 2005 - Tulip- Arthur- ItemView- Scribe- MainWindow
4.1 - 2005- svg- pdf
Minicurso Qt - USP
4.2 - 2006
- Windows Vista- CSS- QGraphicsView
4.3 - 2007
- Melhorias no Vista- Melhorias no SVG- Pdf Print- QScript
Minicurso Qt - USP
4.4 - 2008
- Phonon- XML Aperfeiçoado- QtConcurrent- WebKit- IPC para Threads
4.5 - 2009
- Qt Creator- QGraphicsView++- WebKit++- OpenDocument
Minicurso Qt - USP
4.6 - 2009
- Animações- Gestures- Multi-Touch- Performance++
4.7 - 2010*
- QML- Kinetic
Minicurso Qt - USP
Minicurso Qt - USP
Minicurso Qt - USP
Minicurso Qt - USP
Minicurso Qt - USP
Minicurso Qt - USP
Minicurso Qt - USP
Visão Geral - Qt
Sinais - Slots - Containers - Meta - Objetos - CSS - Scripting - Multimídia - SVG - Bindings Para outras Linguagens - Qwt - Qanava - Wt ( ... )
História
Primeira versão em 1995, por Haavard Nord e Eirik Chambe-Eng;
Iniciou em 1991 e em 1993 já existia um núcleo que suportava widgets;
A letra 'Q' foi escolhida porque era bonita no editor do Haavard;
O “t” vem da palavra toolkit; Em 1994 foi fundada a Trolltech, antes Troll Tech
e ainda antes Quasar Technologies;
Em 1996 foi lançado o Qt 1.1 e a Trolltech tinha 8 clientes;
Também em 1996 o projeto KDE foi fundado por Matthias Ettrich;
O 'K' (do KDE) era simplesmente a letra que vinha antes do 'L';
Em 1997 o Qt passa a ser utilizado no KDE e a versão 1.3 é lançada;
Em 1999, o Qt 2 passa a ser licenciado pela QPL;
História
Em 2000 é lançado o Qtopia (Qt para ambientes embarcados);
Neste mesmo, o Qt passa a ser licenciado pela GPL;
Em 2001 é lançado o Qt3; Em 2005 é lançado o Qt4: primeira versão open-
source em todas as plataformas; Em janeiro de 2008 a Trolltech é comprada pela
Nokia.
História
Hello, Qt
#include <QApplication>#include <QLabel>
int main(int argc, char *argv[]){QApplication app(argc, argv);QLabel l("Oi Mundo");l.show();return app.exec();
}
Para executar:
qmake --projectqmakemake
QMake?
Ferramenta de Gerenciamento da Compilação
Cria e Altera arquivos de Projetos, e manipula Makefiles.
Arquivos .pro devem ser editados manualmente as vezes.
Arquivo de Projeto?
######################################################### Automatically generated by qmake (2.01a) Sat Mar 6 16:50:32 2010########################################################
TEMPLATE = appTARGET = DEPENDPATH += .INCLUDEPATH += .
# InputSOURCES += main.cpp
Sobre o Hello Qt
QApplication:
Controla a camada de eventos, sinais e conexões do Qt.
QLabel:
Um Widget que exibe um texto na tela.
Sinais / Slots : Comunicação entre objetosProperties : Atributos DinâmicosMeta-Objects: Informação de Tipo Eventos e FiltrosTraduções Contextuais.
Modelo de Objetos
Sinais e Slots
- Forma padrão de Comunicação- Só são processados a partir do exec()- Um sinal é uma mensagem enviada.- Um slot é o que fazer quando receber a mensagem.
Conectando Sinais e Slots
#include <QMainWindow>#include <QLabel>#include <QSpinBox>
class Janela : public QMainWindow{Q_OBJECTpublic:
Janela();private:
QLabel m_texto;QSpinBox m_spin;
};
Conectando Sinais e Slots
Janela::Janela() : QMainWindow(){m_texto = new QLabel("");m_spin = new QSpinBox();
connect(m_spin, SIGNAL(valueChanged(QString)),m_texto, SLOT(setText(QString)));
QWidget *centralWidget = new QWidget(this); QHBoxLayout *l = new QHBoxLayout(); l->addWidget(m_texto); l->addWidget(m_spin); centralWidget->setLayout(l); setCentralWidget(centralWidget);}
Sinais
Podem se conectar a vários SlotsPodem se conectar a vários Sinais
connect( m_c1, SIGNAL(triggered()), m_c2connect( m_c1, SIGNAL(triggered()), m_c3connect( m_c1, SIGNAL(triggered()), m_c4
Qual o problema disso? ( Balinha )
Sinais - Sinais
m_b1 = new QPushButton(this);m_b2 = new QPushButton(this);
connect(m_b1, SIGNAL(clicked()), m_b2, SIGNAL(clicked()));
connect(m_b1, SIGNAL(hovered()), m_b2, SIGNAL(hovered()));
connect(m_b1, SIGNAL(activated()), m_b2, SIGNAL(activated()));
Slots - Slots ?
connect(m_b1, SLOT(clicked()), m_b2, SLOT(clicked()));
connect(m_b1, SLOT(hovered()), m_b2, SLOT(hovered()));
connect(m_b1, SLOT(activated()), m_b2, SLOT(activated()));
connect(m_b1, SLOT(clicked()), m_b2, SLOT(clicked()));
connect(m_b1, SLOT(hovered()), m_b2, SLOT(hovered()));
connect(m_b1, SLOT(activated()), m_b2, SLOT(activated()));
Slots - Slots ?
Declarando SIGNALS
class MeuQObject : public QObject{Q_OBJECTpublic:
MeuQObject();signals: ← HÁ!
void meuSinalFofo();void pos3d(int x, int y, int x);void pos2d(int x, int y);
};
Declarando Sinais
NÃO! NÃO! NÃO! NÃO!
void Classe::meuSinalFofo(){...
}void Classe::pos2d(int x, int y){
...}
Como isso funciona?
Usando seus Sinais
void Classe::mouseClick2d(mouse s){QPointF f = s.pos();if ( f.x() < 0 || f.x > screen().size()){
return;}
emit pos2d(f.x(), f.y());}
Criando seus Slots
Class MainWindow::QMainWindow{Q_OBJECTpublic:
MainWindow();
private slots:void setPonto2d(int x, int y);void setX(int x);void setY(int y);
}
Criando seus Slots
void MainWindow::setPonto2d(int x, int y){setX(x);setY(y);
}
void MainWindow::setX(int x){ m_x = x; }
void MainWindow::setY(int y){ m_y = y; }
Seus Sinais + Seus Slots
MainWindow::MainWindow(){MeuQObject *o = new MeuQObject();connect(o, SIGNAL(pos2d(int,int))
this, SLOT(setPos(int,int)));connect(o, SIGNAL(pos2d(int,int)),
this, SLOT(setX(int)));connect(o, SIGNAL(pos2d(int,int)),
this, SLOT(setY(int))); ← BALINHA!}
Calculadora + Designer
Designer
Caixa de Ferramentas
Botões, Caixas,Textos, Layouts,Controles, Radios,etc.
Editor de Propriedades do Objeto
Designer
Voltando a Calculadora
Voltando a Calculadora
Layouts
Organização de Widgets na Tela
- Verticais- Horizontais- Formulários em Colunas- Grade- Expansiveis via Sobrecarga
Layouts
o Calc.ui amava o ui_calc.hque amava o calc.hque amava o calc.cppQue não amava ninguem.e o QWidget segurava vela.
Ciranda
QChar sinal; bool esperandoPorSinal; void calcular(QChar s);
private slots: void numPressed(); void enterPressed(); void clearPressed(); void signalPressed();};
class Calc : public QWidget,public Ui::calc{
Q_OBJECT public: Calc(); private: QString numero; QString memoria;
Calc.h
foreach(QPushButton *b, botoes){ connect(b, SIGNAL(clicked()),
this, SLOT(numPressed())); }
connect(benter, SIGNAL(clicked()),
this, SLOT(enterPressed())); connect(bclear, SIGNAL(clicked()),
this, SLOT(clearPressed()));}
Calc::Calc()
Calc::Calc(){ setupUi(this); numero = "0"; memoria = "0"; lcd->display(numero); QList<QPushButton*> botoes; botoes << b1 << b2 << b3 << b4 << b5 << b6 << b7 << b8 << b9 << b0;
void Calc::clearPressed(){ memoria = '0'; numero = '0'; lcd->display(numero);}
void Calc::signalPressed(){ numero = QString(); QPushButton *b = sender(); sinal = b->text()[0];}
Calc::*Pressed()
void Calc::numPressed(){ QPushButton *b = sender(); numero += b->text(); lcd->display(numero);}
void Calc::enterPressed(){ calcular(sinal); numero = QString();}
Calc::calcular()
void Calc::calcular(QChar s){ qreal n1 = memoria.toDouble(); qreal n2 = numero.toDouble();
switch( s.toAscii() ){ case '+' : n1 += n2; break; case '-' : n1 -= n2; break; case '*' : n1 *= n2; break; case '/' : n1 /= n2; break; } memoria = QString("%1").arg(n1); lcd->display(memoria); }
Sinais - Slots
QLayouts - De novo =)
#include <QWidget>#include <QApplication>#include <QList>#include <QPushButton>#include <QVBoxLayout>#include <QHBoxLayout>
int main(int argc, char *argv[]){QApplication app(argc, argv);
QWidget *janela = new QWidget();QVBoxLayout *layout1 = new QVBoxLayout();QVBoxLayout *layout2 = new QVBoxLayout();QHBoxLayout *layoutCentral = new QHBoxLayout();
for(int i = 0; i < 10; i++){QPushButton *b = new QPushButton(janela);b->setText(QString("Botao n%1").arg(i));if (i%2){
layout1->addWidget(b);}else{
layout2->addWidget(b);}
}layoutCentral->addLayout(layout1);layoutCentral->addLayout(layout2);janela->setLayout(layoutCentral);janela->show();return app.exec();
}
Parentesco
Widgets tem Pais.O Pai de Todos tem parent() == 0
Widgets mortos, Matam os filhos junto.
Propagam Eventos pela arvore de parentesco.
Parentesco
Manipulador de Imagens
Manipulador de Imagens
class JPrincipal : public QWidgetprivates: void adicao() void subtracao() void negativa() void threshould() void tonsDeCinza() void historigrama()
Class JPrincipal : Membros
private: QLabel *m_image; QSlider *m_red; QSlider *m_green; QSlider *m_blue; QComboBox *m_opcoes;
QSlider
Seleção de Valores em uma faixa
sinais:valueChanged()sliderPressed()sliderMoved()sliderReleased()
QLabel
Guarda TextoGuarda ImagemGuarda Animação
Ultra - Versátil =)
QComboBox
Valores em Drop - DownAceita modelsAceita listasAceita adição - na - mão.
Construtor
m_red = new QSlider(Qt::Horizontal, this);
m_red ->setRange(0, 255);
m_image = new QLabel("Imagem Aqui", this);
m_opcoes = new QComboBox(this);
m_opcoes->addItem(tr("Adicao"));
QHBoxLayout *h = new QHBoxLayout();
h->addWidget(m_red);
Construtor
QVBoxLayout *v = new QVBoxLayout(this);v->addWidget(m_image);v->addWidget(m_opcoes);v->addLayout(h);
connect(m_opcoes, SIGNAL(currentIndexChanged(QString)), this, SLOT(executeAlgorithm(QString)));
connect(m_red, SIGNAL(sliderReleased()), this, SLOT(intCanais()));
executeAlgorithm
void JPrincipal::executeAlgorithm(const QString &s){ /* */if ( s == "Adicao") adicao (); else if ( s == "Subtracao") subtracao (); else if ( s == "Negativa") negativa (); else if ( s == "Threshould") threshould (); else if ( s == "TonsDeCinza") tonsDeCinza (); else if ( s == "Historigrama") historigrama ();}
void JPrincipal::tonsDeCinza(){ QPixmap p("imagem.jpg"); QImage i = p.toImage().scaled(QSize(800,600)); for( int row = 0; row < i.width(); ++row){ for( int column = 0; column < i.height(); ++ column){ QColor pixel = i.pixel(row, column); uint total = (pixel.red() *0.299f) + (pixel.green() * 0.587f) + (pixel.blue() * 0.114f); QColor c(total, total, total); i.setPixel(row, column, c.rgb() ); } }
p = p.fromImage(i); m_image->setPixmap(p); }
Tons de Cinza
Limiar
void JPrincipal::threshould(){ QPixmap p("/home/tomaz/Multimedia/Fotos/Bella/bella.jpg"); QImage i = p.toImage().scaled(QSize(800,600)); for( int row = 0; row < i.width(); ++row){ for( int column = 0; column < i.height(); ++ column){ QColor c = i.pixel(row, column); qreal limiar = c.blueF() + c.redF() + c.greenF();; i.setPixel(row, column, (limiar > 2.5f) ? 0xFFFFFF : 0x0); } } p = p.fromImage(i); m_image->setPixmap(p);}
Negativa
void JPrincipal::negativa(){ QPixmap p("foto.jpg"); QImage i = p.toImage().scaled(QSize(800,600)); for( int row = 0; row < i.width(); ++row){ for( int column = 0; column < i.height(); ++ column){ QColor c = i.pixel(row, column); c = QColor(255-c.red(), 255-c.green(), 255-c.blue()); i.setPixel(row, column, c.rgb()); } } p = p.fromImage(i); m_image->setPixmap(p);}
Resultado
QPixmap
Otimizada para representar ImagensPode ser usada em QLabel, QPushButtonCompartilhamento Implicito de dadosCarregado de um QImage
QImage
Manipulação de BitsPode ser usado com painterexecução supimpa em acesso de bitsthread safe =D
QColor
Representa uma cor
Widgets que Não Existem?
void JPrincipal::historigrama(){ QPixmap p("fotos.jpg");
THistorigram *t = new THistorigram(p);
t->resize(255,255); t->show();
p = p.fromImage(i); m_image->setPixmap(p);}
THistorigram::THistorigram(QPixmap p, QWidget *parent) : QWidget(parent){ m_r.resize(255); m_g.resize(255); m_b.resize(255); QImage i = p.toImage().scaled(QSize(800,600)); for( int row = 0; row < i.width(); ++row){
for( int column = 0; column < i.height(); ++ column){ QColor c = i.pixel(row, column); if (c.red() != 0){ m_r[c.red()-1 ] += 1; } if (c.green() != 0){ m_g[c.green()-1] += 1; } if (c.blue() != 0){ m_b[c.blue()-1 ] += 1; } } }
setBackgroundRole(QPalette::Base); setAutoFillBackground(true);}
thistorigram.h
QSize THistorigram::minimumSizeHint() const{ return QSize(255, 255); }QSize THistorigram::sizeHint() const{ return QSize(255, 255); }
void THistorigram::paintEvent ( QPaintEvent * /*event*/ ){ QPainter p(this); QLine line;
int max = 0; p.setPen(Qt::red); drawLines(p, max, m_r); p.setPen(Qt::green);drawLines(p, max, m_g); p.setPen(Qt::blue); drawLines(p, max, m_b); if (height() != max){ resize(255, max); } }
Historigrama =D
drawLines
void THistorigram::drawLines(QPainter &p, int& max, QVector<int>& vetor){ for(int i = 0; i < 250; ++i){ int p1 = vetor[i]/10; int p2 = vetor[i+1]/10; if (p1 > max) max = p1; if (p2 > max) max = p2; p.drawLine(i, p1, i+1, p2); }}
ResultadoQPainter
pintura low levelQPen
cor, estilo e espessura da linhaQBrush
balinha.
sizeHintminimumSizeHint
Pai de Todos - QMainWindow
QMenuBar- Menus de Opções
QToolBar- Icones de Opções
QDockWidget- Caixas flutuantes
QStatusBar- Status do aplicativo
QWidget- Centro do programa
QMenuBar
Relacionados:QMenuQAction
Container de MenusCada Menu Guarda MenusCada Menu Guarda QActionsCada Menu Guarda Separadores
QToolBar
Relacionados:QAction
Cada QToolBar contem n QActionsCada QToolBar é MóvelCada QToolBar pode ser EscondidaCada QToolBar pode escolher onde ficar
QActions?
Sim.
Consistência entre Menu e ToolbarQuando ativado, triggered();Imagem, Tooltip, Texto, Formato, etc.
Diga não a Duplicação de código com QAction.
Escrevendo Feliz
Escrevendo Feliz
#include <QApplication>#include "dfeliz.h"int main(int argc, char *argv[]){
QApplication app(argc, argv);DFeliz janela;janela.show();return app.exec()
}
Escrevendo Feliz - QActions
void DFeliz::setupActions(){ m_save = new QAction("Save", this); m_save->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S)); connect(m_save, SIGNAL(triggered()), this, SLOT(save_file())); m_new = new QAction("New", this); m_new->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_N)); connect(m_new, SIGNAL(triggered()), this, SLOT(new_file()));}
Escrevendo Feliz - Menus
void DFeliz::setupUi(){ QMenuBar *m = menuBar(); QMenu *fileMenu = m->addMenu(tr("&File")); fileMenu->addAction(m_new); fileMenu->addAction(m_save);
QToolBar *toolBar = addToolBar(tr("Principal")); toolBar->addAction(m_new); toolBar->addAction(m_save);}
Salvando o Arquivo
void DFeliz::save_file(){ m_file = QFileDialog::getSaveFileName (); if ( m_file.isEmpty() ) return; QFile file(m_file); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return;
QTextStream out(&file); out << m_textEdit->toPlainText(); file.close();}
class DFeliz : public QMainWindow {Q_OBJECTpublic: DFeliz();private: QAction *m_new; QAction *m_save; QAction *m_cut; QAction *m_paste; QTextEdit *m_textEdit; QString m_file;private slots: void new_file(); void save_file();};
Classinteira ;)
Implementem o resto
cut, copy, paste, e abrir arquivo.
vamos. Enquanto isso eu ando de um lado pra o outro e ignorando pedidos de ajuda por uns 5 minutos.
QThread
Threads MultiplataformaPThreads no LinuxWindows::Threads no Windows
Gerenciamento de Sinais / Slots
QObjects? NahQWidgets? Nah
Exemplo de Threads
class MainWindow : public QMainWindow{Q_OBJECT
public: MainWindow(QWidget *parent = 0); private: ThreadReader* grupo1; ThreadCreator* grupo2; QStringList bagOfTasks; QMutex read; QMutex write;};
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ QHBoxLayout *l = new QHBoxLayout(); QTextEdit *e; for (int i = 0; i < 5; i++){ e = new QTextEdit(this); l->addWidget(e); grupo1 = new ThreadReader(bagOfTasks, read); grupo2 = new ThreadCreator(bagOfTasks, i, write); connect(grupo1, SIGNAL(sendMessage(const QString&)),
e, SLOT(append(const QString&))); grupo2->start(); grupo1->start(); }
QWidget *centralWidget = new QWidget(this); setCentralWidget(centralWidget); centralWidget->setLayout(l); }
MainWindow
void ThreadCreator::update(){ if (_bag.size() >= 20) return; _mutex.lock(); QString conteudo; for(int i = 0; i < 4; i++) conteudo += QChar(rand()%65 + 32); _bag << QString("Thread %1 \t %2 \t %3 ") .arg(_number) .arg(conteudo) .arg(_total++); _mutex.unlock(); }
Thread::Criador
void ThreadCreator::run(){ QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout()),
this, SLOT(update())); timer->start(250); exec();}
Thread::Criador
void ThreadReader::update(){ if (_bag.empty()) return; _mutex.lock(); emit sendMessage(_bag.takeFirst()); _mutex.unlock();}
Thread::Leitor