1

voila, je voudrais faire une application style API win32 avec une fenêtre qui se dessine grâce à une méthode "paint"

en gros, je voudrais juste dessiner des lignes, pixels, toussa sur une fenêtre, et exécuter du code quand on bouge la souris.

et je voudrais que ce soit portable, donc j'ai choisi QT (non négociable).

mais mon incompétence crasse en c++ (c'est même pas à cause de QT là triso) me joue des tours

pour le moment j'ai 3 fichiers:

ec(); }
main.cpp#include "mainform.h"

#include <QApplication>

int main(int argc, char* argv[])
{
    QApplication app(argc, argv);
	mainform mf;
	mf.resize(400,400);
	mf.show();
    return app.ex


H_INCLUDED
mainform.h#ifndef MAINFORM_H_INCLUDED
#define MAINFORM_H_INCLUDED

#include <QMainWindow>

class mainform : public QMainWindow
{
	Q_OBJECT

public:
	mainform(QWidget *parent = 0);
};

#endif // MAINFORM_


return; }
mainform.cpp#include "mainform.h"

mainform::mainform(QWidget *parent): QMainWindow(parent)
{
	this->setWindowTitle("test");


je compile ça avec un makefile, classique, les libs Qt sont accessibles.

mais g++ se plaint de pas trouver de vtable (undefined reference to vtable for mainform) à la ligne 4 de mainform.cpp...
qu'est ce que j'ai fait pour qu'il pleure autant? sad

2

j'obtiens la même chose en collant les 3 fichiers dans 1 seul.

edit: bon, c'est Q_OBJECT qui empêche de compiler. Ca sert à quoi, ça? hum

edit2: hum, sympa, pas besoin de se faire chier avec des signaux et slots, suffit de surcharger les Event grin

3

Q_OBJECT est une macro que tu dois définir pour les classe qui héritent des classes QT. C'est elle qui permet entre autre de faire fonctionner le mécanisme des signaux/slots.
avatar

4

Oui, mais je ne comprends pas pourquoi cela ne compilait pas...

[edit] D'ailleurs je viens de tester chez moi ça compile confus
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

5

(cross) oué, j'ai bien pigé que c'était pour les signal/slots/toussa, mais pourquoi il chie sur la vtable toussa quand je le mets? je dois la définir? comment? confus

sEvent(QMouseEvent * e); void mainform::mouseReleaseEvent(QMouseEvent *e); };
bon, en fait, je m'en suis sorti en surchargeant les méthodes *Event comme ça:class mainform : public QMainWindow
{
	//Q_OBJECT

public:
	mainform(QWidget *parent = 0);
	void mainform:: paintEvent(QPaintEvent *e);
	void mainform::mouseMoveEvent(QMouseEvent * e);
	void mainform::mousePres

c'est exactement ce que je cherchais en fait love

allez, [jeu] qui sera le premier à me dire que c'est obsolète, pas ça, ou mal fichu? grin

6

Pour une application QT, il est conseillé de ne pas utiliser de makefile classique mais de laiser l'outil qmake le générer. En effer QT a recours a divers outils qui génèrent du code en particulier pour l'utilisartion des sigaux/slots.

Tu fais un fichier "MonProjet.pro" Le plus simple est de laisser qmake le générer avec la commande "qmake -project"
Ensuite tu fais "qmake" pour générer le makefile correspondant au projet puis "make" pour compiler.
avatar

7

oué, je connais, sauf que je n'utilise aucun fichier .ui pour le moment, juste une fenêtre sur laquelle je dessine à coup de painter grin

du coup, pas besoin de qmake pour le moment, j'utilise code::blocks smile

8

Il n'y a pas que l' outil ui qui génère du code. Si tu utilises certaine fonction comme les signaux/slots, tu auras besoin de l'outil "moc" qui va générer des fichiers C++.
Le Q_OBJECT sert en autre aux fichiers qui doivent être traités par "moc", ce qui explique qu'il ne trouve pas le code qui est sensé être généré.

Et donc si tu ne veux pas te prendre la tête a comprendre le fonctionnement de moc, il vaut mieux prendre l'habitude d'utiliser qmake. Pour le moment tu peux y échapper car l'appli est simple, mais si jamais elle se complique, tu en auras sans doute besoin.
avatar

9

sasume:~/test$ ls
mmain.cpp mmainform.cpp mainform.h
sasume:~/test$ cat main.cpp
#include "mainform.h" 
 
#include <QApplication> 
 
int main(int argc, char* argv[]) 
{ 
    QApplication app(argc, argv); 
        mainform mf; 
        mf.resize(400,400); 
        mf.show(); 
    return app.exec(); 
}
sasume:~/test$ cat mainform.h
#ifndef MAINFORM_H_INCLUDED 
#define MAINFORM_H_INCLUDED 
 
#include <QMainWindow> 
 
class mainform : public QMainWindow 
{ 
        Q_OBJECT 
 
public: 
        mainform(QWidget *parent = 0); 
}; 
 
#endif // MAINFORM_H_INCLUDED
sasume:~/test$ cat mainform.cpp
#include "mainform.h" 
 
mainform::mainform(QWidget *parent): QMainWindow(parent) 
{ 
        this->setWindowTitle("test"); 
        return; 
}
sasume:~/test$ qmake -project
sasume:~/test$ qmake
sasume:~/test$ make
g++ -c -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I../kde/src/qt-copy/mkspecs/linux-g++ -I. -I../qt-copy/include/QtCore -I../qt-copy/include/QtCore -I../qt-copy/include/QtGui -I../qt-copy/include/QtGui -I../qt-copy/include -I. -I. -I. -o main.o main.cpp
g++ -c -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I../kde/src/qt-copy/mkspecs/linux-g++ -I. -I../qt-copy/include/QtCore -I../qt-copy/include/QtCore -I../qt-copy/include/QtGui -I../qt-copy/include/QtGui -I../qt-copy/include -I. -I. -I. -o mainform.o mainform.cpp
/home/kde-devel/qt-copy/bin/moc -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I../kde/src/qt-copy/mkspecs/linux-g++ -I. -I../qt-copy/include/QtCore -I../qt-copy/include/QtCore -I../qt-copy/include/QtGui -I../qt-copy/include/QtGui -I../qt-copy/include -I. -I. -I. mainform.h -o moc_mainform.cpp
g++ -c -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I../kde/src/qt-copy/mkspecs/linux-g++ -I. -I../qt-copy/include/QtCore -I../qt-copy/include/QtCore -I../qt-copy/include/QtGui -I../qt-copy/include/QtGui -I../qt-copy/include -I. -I. -I. -o moc_mainform.o moc_mainform.cpp
g++ -Wl,--no-undefined -o test main.o mainform.o moc_mainform.o    -L/home/kde-devel/qt-copy/lib -lQtGui -L/home/kde-devel/qt-copy/lib -L/usr/X11R6/lib -lpng -lSM -lICE -pthread -pthread -lXi -lXrender -lXrandr -lfreetype -lfontconfig -lXext -lX11 -lQtCore -lz -lm -pthread -lgthread-2.0 -lrt -lglib-2.0 -ldl -lpthread
sasume:~/test$


(j'utilise Qt 4.4)
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

10

squalyl (./5) :
allez, [jeu] qui sera le premier à me dire que c'est obsolète, pas ça, ou mal fichu? grin
Jette quand même un coup d'oeil là-dessus pour ne pas t'embarquer dans une solution qui s'avèrerait inutilisable a posteriori http://doc.trolltech.com/4.3/eventsandfilters.html
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

11

./9 En effet, comme je disais, le problème viens du fait que le Q_OBJET réclame que le fichier soit traité par "moc". Celui-ci va génerer un code en c++ nécessaire pour certaines fonctionnalités avancées comme les signals/slots.

Donc, soit il faut utiliser "moc" dans le makefile, ou plus simple, laisser qmake s'en charger.
avatar

12

(oui, j'ai eu la révélation du lien Q_OBJECT <=> moc aux chiottes triso)

mais comme j'utilise que du c++ standard avec des Events, j'ai pas besoin de moc.

Sasume:
j'ai pas compris pourquoi ça deviendrait inutilisable confus
c'est exactement ce que j'attends d'un tel mécanisme.

13

Non non je ne voulais pas dire que tu avais tout faux, je t'ai juste donné un lien où est expliqué le fonctionnement de la gestion des évènements de Qt pour que tu t'assures que ce que tu fais n'est pas mauvais ou qu'il n'y a pas une méthode plus attendue ou plus simple pour parvenir au même résultat.
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

14

ok, merci alors smile

donc, oué, c'est exactement ça que je cherchais et love ça ressemble bcp aux évènements d'AWT #troll# (et accessoirement aux WndProc de win32 et toussa ^^)

15

Et pour continuer le #troll# qui va faire venir KK ici en quatrième vitesse.

Je dirais que la partie graphique de QT se rapproche énormément de JAVA au niveau de son fonctionnement, surtout depuis les version 4.x. Elle récupère au passage la plupart de ses avantages et de ses défauts. Enfin on est pas trop dépaysé de passer de QT à JAVA et vice versa. la seule différence à assimiler c'est signal vs listener.
avatar

16

j'ai toujours pas pigé les signaux, et feignasse comme je suis, si les callbacks marchent, je vais pas chercher plus loin grin

17

Un signal est émis par une classe (quelconque) pour notifier d'un évènement particulier que d'autres classes sont intéressées de connaître (classes Listener en Java).
Le code à exécuter par la classe qui "écoute" ces émissions de signaux sont des slots.
Donc plutôt que d'ajouter une classe comme étant un "listener", en Qt on ne fait qu'indiquer pour tel signal quel est le code (slot) à exécuter.
On peut aussi connecter un signal à un autre signal pour déclencher des cascades de signaux.
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

18

J'explique l'erreur de la vtable: pour éviter de générer plusieurs copies de la vtable (ce qui fait du boulot pour le linker qui doit en retenir une seule), g++ émet la vtable dans le fichier C++ qui implémente la première fonction virtuelle à ne pas être implémentée inline à l'intérieur de la déclaration de la classe. Or, dans le cas de Qt, cette méthode se trouve dans la macro Q_OBJECT, et son implémentation dans l'objet généré par moc. Donc si tu ne lances pas moc, il te manquera la vtable.

Quant à évènements (dans le contexte de Qt, ce mot signifie "méthodes virtuelles de traîtement d'évènements à surcharger") vs. signaux, ce qu'il faut utiliser dépend du contexte. Normalement, ce sont des signaux, mais quand c'est quelque chose qui est normalement géré par la classe elle-même, un évènement est utilisé pour des raisons de performance. Pour paint, c'est bien l'évènement qu'il faut surcharger, mais dans la plupart des cas, tu es censé passer par des signaux et slots.

Et c'est Qt avec un 't' minuscule!
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

19

ok chef, j'ai tout noté smile

; void mouseReleaseEvent(QMouseEvent *e); private: //blabla };
alors en gros pour faire tout bien, là j'ai une classe comme ça:class mainform : public QMainWindow
{
public:
	mainform(QWidget *parent = 0);

	void resizeEvent(QResizeEvent *e);
	void paintEvent(QPaintEvent *e);
	void mouseMoveEvent(QMouseEvent * e);
	void mousePressEvent(QMouseEvent * e)


je devrais faire quoi pour utiliser des signaux a la place des machins de souris?

...
private:
	void paintEvent(QPaintEvent *e);
private slot:
	void resizeEvent(QResizeEvent *e);
	void mouseMoveEvent(QMouseEvent * e);
	void mousePressEvent(QMouseEvent * e);
	void mouseReleaseEvent(QMouseEvent *e);

et puis mettre quoi? je suppose qu'il y aura des appels à connect() dans le constructeur... (je pourrais tester direct, mais je l'écris pour google)

(et pas besoin que ces membres surchargés soient publics, je suppose que ça suffit de les mettre privé...)

20

hum, petit doute: si j'affecte une variable locale à un paramètre qui est une référence, ça copie les données ou ça se comporte comme un pointeur? ie est ce que
void classe::getValeur(ObjetPerso &o)
{
  ObjetPerso p;
  p=machin();
  o=p;
}
fonctionnera sans erreur en copiant les données de p dans o, comme ce que j'obtiendrai en C avec:
void getValeur(Objet *o)
{
  Objet p;
  memcpy(o,&p,sizeof(p));
}

edit: apparemment oui, ça fait ce que je veux, ie copier tous les champs vers l'objet référencé

21

et j'ai des problèmes (je maitrise pas tout) en castant des objets en références sad

exemple:

gv.setCenter((QPoint&)QPoint(e->size().width()/2, e->size().height()/2));
et ça marche pas, évidemment. j'ai cette erreur:
conversion to non-const reference type `class QPoint&' from rvalue of type `QPoint'

e->size() est un QSize, je voudrais le "point au centre" smile

je fais QPoint(x,y) ce qui me donne un objet temporaire de type QPoint, mais après, je suis emmerdé, parce que je voudrais transformer ça en référence... bref, la galère du débutant quoi grin

rationale: j'aimerais bien mettre des références ici, pour éviter de mettre un objet tout court en paramètre, ce qui d'après moi va passer tout plein de trucs par la pile... ptet que je suis a coté de la plaque?

ize().height()/2); gv.setCenter(p);edit: j'ai remplacé cette ligne par: QPoint p(e->size().width()/2, e->squi fonctionne, mais je comprends pas comment le faire en 1 ligne!

22

c'est pas l'appelant qui décide de cela, mais l'appelé.
En gros tu regardes le prototype de la fonction que tu appelles et tu seras si c'est par référence, pointeur ou valeur.
Sinon merci QT pour ce truc infame de Q_Object... vive les bidouilleurs.

23

squalyl (./20) :
hum, petit doute: si j'affecte une variable locale à un paramètre qui est une référence, ça copie les données ou ça se comporte comme un pointeur?

Ça se comporte comme un pointeur.
squalyl (./21) :
et j'ai des problèmes (je maitrise pas tout) en castant des objets en références sad

Tu ne peux pas caster les objets en références (en références const peut-être, mais ça ne sert à rien), et si la fonction attend un paramètre par valeur, il sera de toute façon passé par valeur. Je te signale que QPoint est un objet de 8 octets, ça ne sert pas à grand chose de le passer par référence.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

24

Les signals/slots servent plutôt à la communication entre différents widgets. Par exemple, tu peux "exporter" une interface pour ton widget particulier à travers quelques signals auxquels seront susceptibles de se connecter d'autres widgets. Mais pour implémenter un comportement de widget particulier, je pense que ta méthode consistant à customiser la réponse à certains évènements est la bonne.
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

25

ok, merci pour ton appréciation happy
JackosKing (./22) :
Sinon merci QT pour ce truc infame de Q_Object... vive les bidouilleurs.

oué, t'as vu, j'ai tout viré et ça marche niquel pour mon utilisation hehe
Kevin Kofler (./23) :
Ça se comporte comme un pointeur.

apparemment, ça copie aussi sorry

si ça se comportait comme un pointeur, ça déconnerait, parce que j'affecterais un truc qui a une adresse dans la pile ( et qui n'est plus valide à la sortie de la fonction) hehe

26

Non non, ce qu'il veut dire c'est que dans le code appelant la fonction, l'objet que tu passes en paramètre sera modifié par la fonction (comme en Java).
Alors que si c'était un passage par valeur, l'objet du code appelant n'aurait pas été modifié (puisqu'il aurait été copié avant que la fonction ne soit appelée).
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

27

28

Non, je veux bien dire que ça se comporte à plein effet comme un pointeur! Une référence en C++ est un pointeur, sauf que les opérations & et * sont implicites.

La raison pour laquelle ça ne foire pas est parce que la fonction appelée ne stocke pas la référence, soit elle l'utilise seulement jusqu'à son retour, soit elle la copie. Mais attention, le C++ n'oblige pas les fonctions à faire ça, donc il y a des fonctions qui gardent leurs références, par exemple la référence sur argc dans le constructeur de QApplication (la documentation dit: "Warning: The data pointed to by argc and argv must stay valid for the entire lifetime of the QApplication object.").
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

29

squalyl (./25) :
oué, t'as vu, j'ai tout viré et ça marche niquel pour mon utilisation hehe

La documentation de Qt dit qu'il ne faut surtout pas dériver d'un QObject sans mettre la macro Q_OBJECT, il y a des cas où ça peut foirer, par exemple le nom de classe donné par le système QMetaObject ne sera pas bon.

Cela dit, je l'ai fait aussi quelques fois et ça a marché... (M'en fous du nom de classe donné par QMetaObject.)
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

30

ouais. je vois.

on va dire que pour le moment, ça marche, et si ça foire, je chercherai de ce coté là.

sinon je passe tout en pointeurs "comme java" et j'expliciterai les copies #bourrin# grin