PDA

View Full Version : problem with Qt



deeee
21st May 2010, 21:58
Hello,
I'm trying to make a button in the menu bar that allows to display a sub window of type QDockWidget.
The problem is that the slot that displays the window can't have arguments because the signal 'triggered' of QAction doesn't have any.
Actually, I didn't find a predefined slot that allows to do what I want so I tried to make my own slot display() and inside it there's only a show().
The problem is that I can't choose which window I want to display because the signal and the slot must have the same number of arguments.

Here is my code.
I'm trying to implement a function that allows to display 'palette' after it has been accidently closed by the user.

#include "FenPrincipale.h"

FenPrincipale::FenPrincipale()
{
//creation of the menu
QMenu *menuFichier = menuBar()->addMenu("&Fichier");

QAction *actionQuitter = menuFichier->addAction("&Quitter");
actionQuitter->setShortcut(QKeySequence("Ctrl+Q"));
actionQuitter->setIcon(QIcon("quitter.png"));

QMenu *menuEdition = menuBar()->addMenu("&Edition");
QMenu *menuAffichage = menuBar()->addMenu("&Affichage");

// Création de la barre d'outils
QToolBar *toolBarFichier = addToolBar("Fichier");
toolBarFichier->addAction(actionQuitter);
toolBarFichier->addSeparator();
QFontComboBox *choixPolice = new QFontComboBox;
toolBarFichier->addWidget(choixPolice);

// Creation of the docks
QDockWidget *dock = new QDockWidget("Palette", this);
addDockWidget(Qt::LeftDockWidgetArea, dock);

QWidget *contenuDock = new QWidget;
dock->setWidget(contenuDock);

QPushButton *crayon = new QPushButton("Crayon");
QPushButton *pinceau = new QPushButton("Pinceau");
QPushButton *feutre = new QPushButton("Feutre");
QLabel *labelEpaisseur = new QLabel("Epaisseur :");
QSpinBox *epaisseur = new QSpinBox;

QVBoxLayout *dockLayout = new QVBoxLayout;
dockLayout->addWidget(crayon);
dockLayout->addWidget(pinceau);
dockLayout->addWidget(feutre);
dockLayout->addWidget(labelEpaisseur);
dockLayout->addWidget(epaisseur);

contenuDock->setLayout(dockLayout);

// Création of the central zone
QWidget *centralzone = new QWidget;
setCentralWidget(centralzone);

connect(actionQuitter, SIGNAL(triggered()), qApp, SLOT(quit()));
}





I hope you have understood me, if not please ask for further details.
Thanks

wysota
21st May 2010, 23:36
Have a look at QDockWidget::toggleViewAction(). You don't have to make your own workarounds when ready-made solutions are available.

deeee
22nd May 2010, 00:50
Thanks a lot for your answer.
It still wonder how to do it generally speaking though because I have faced this problem more than once, and I can't find the solution.
How can I access a variable with a slot if the variable is declared in a class and the slot if defined outside the class ???
It seems to me that I can't pass it as an argument, because the triggered signal is of a fixed type.
Even if I know which function to use (toggleviewaction), I still don't know how to call this function once I have received the signal "triggered" from my button.

Please help me to understand how to do that.
Thanks.

wysota
22nd May 2010, 02:16
This is more object-oriented programming issue than anything Qt related. You should be able to come to your own conclusions here. It's all just a matter of exposing proper methods from objects/classes.

deeee
22nd May 2010, 03:01
Yes I know this is easy but I just don't know how to do it.
I've just started using qt and I know very little about C++.
Can you help me please ?

Thanks a lot.

wysota
22nd May 2010, 05:09
I've just started using qt and I know very little about C++.
So please do yourself a favour and get a decent knowledge of C++ first.

To be honest I don't understand your problem... You are given an action which toggles whether the dock widget is shown or not and updates its state automatically based on the state of the dock widget. What more do you want?

deeee
22nd May 2010, 15:41
Let me try to explain myself better then.
My problem is that my dock widget is defined in a function but is used in another one. How can I access it ?
I can't pass it as an argument because the signal is of fixed type and thus so is the function I want to create.

More specifically (see the code above) :
my dock widget is defined in the class FenPrincipale.
I want to create a button that displays this dock when it is checked.
This button sends a triggered signal when it is clicked on, and I want to connect it to a function called display_dock that is basically like this :
void FenPrincipale::display_dock()
{
dock.ToggleViewAction();
}

The problem is that 'dock' is not defined in this function, and I can't pass it as an argument because the signal triggered() is of fixed type.

tbscope
22nd May 2010, 18:00
This is basic C++ and Object Oriented Programming.

Here's what you do:

FenPrincipale::FenPrincipale()
{
...

// Creation of the docks
QDockWidget *dock = new QDockWidget("Palette", this);
addDockWidget(Qt::LeftDockWidgetArea, dock);

...
}


You define a QDockWidget object called dock inside the scope of your constructor. The scope is between the { and }
This means that the object dock is only available inside this scope, thus only in the constructor.
What you want to do is, define the object dock in a place where it is more accessible. To do that, you use the class definition. You define objects you want to use globally in your class in the definition of your class, not the implementation of your constructor.

Example:


class FenPrincipale : public QWidget
{
Q_OBJECT

public:
FenPrincipale(QWidget *parent = 0);

...

private:
QDockWidget *dock;
};

As you see above, I've defined a private QDockWidget object called dock. (Note that the ... is just to denote that there might be more lines there).
As it is a pointer, you have to create a new object with the new statement. This can be done in your constructor:


// Look at the constructor too, I passed a parent here
FenPrincipale::FenPrincipale(QWidget *parent)
: QWidget(parent)
{
...

// Creation of the docks
// This was your line:
// QDockWidget *dock = new QDockWidget("Palette", this);
// This is the one I suggest:
dock = new QDockWidget("Palette", this);
// See the difference?
addDockWidget(Qt::LeftDockWidgetArea, dock);

...
}


Now, you can access the object dock from every function within your class.
Example:



FenPrincipale::FenPrincipale(QWidget *parent)
: QWidget(parent)
{
...

// Creation of the docks
// This was you line:
// QDockWidget *dock = new QDockWidget("Palette", this);
// This is the one I suggest:
dock = new QDockWidget("Palette", this);
// See the difference?
addDockWidget(Qt::LeftDockWidgetArea, dock);

...
// Create a slot and connect a signal to it:
connect(someActionObject, SIGNAL(triggered()), this, SLOT(showPaletteDock()));
...
}

void FenPrincipale::showPaletteDock()
{
dock->toggleViewAction();
}


Basic C++

deeee
22nd May 2010, 18:17
seems obvious now.
thanks a lot for your explanation, very instructive.

I have a small unrelated problem, but I'd like to ask it here instead of making a new thread, if you don't mind, because you seem to know quite a lot about this stuff.
I'd like to display some numbers and words in a 2 dimensional array. I tried QTableWidget but this class is far too complex, the user can edit it whereas I only want to display it. Any ideas ?

tbscope
22nd May 2010, 18:21
A table widget is actually the best way to display 2d data (well, I like to think so).
You can disable the edit triggers by using:
setEditTriggers(QAbstractItemView::NoEditTriggers)

deeee
22nd May 2010, 19:03
Do you really have a fast answer to everything ? :D
Is there a way I can make the cells change their sizes according to their contents?
Similarly, Is there a way I can make the whole table change its size according to its content? (if the table is too small, scrolls appear, and I'd like to avoid that).

I have another question that will more likely match your skills.
I'm trying to use QTextEdit.
First I'd like to know how to access its content and how to write stuff into QTextEdit, but I'm guessing this is easy for you.
Now what I'd like to do is to display the line number in front of each line, as it is done in many editors. I assume this is less easy, but I hope you'll be able to help me.

Thanks a lot for your help so far, I find it really useful and instructive.

tbscope
22nd May 2010, 20:13
but I'm guessing this is easy for you.
It's easy for you too :-)
Go to this site:
http://doc.qt.nokia.com/4.6/index.html


Is there a way I can make the cells change their sizes according to their contents?
Of course:
Use horizontalHeader () const : QHeaderView * to get the header view of your table. The header view are the column names.
The header view has a member function to set the the resize mode, conveniently called setResizeMode(...)
Set one or all columns to QHeaderView::ResizeToContents
Maybe do the same for verticalHeader


Similarly, Is there a way I can make the whole table change its size according to its content? (if the table is too small, scrolls appear, and I'd like to avoid that).
I'm not sure what you mean. Do you want to make the window bigger?


First I'd like to know how to access its content and how to write stuff into QTextEdit
As said in the beginning, read the documentation. This is straightforward.


Now what I'd like to do is to display the line number in front of each line, as it is done in many editors. I assume this is less easy, but I hope you'll be able to help me.
This depends on how you want to do this. The simple, lazy way is to just prepend a line number to each text line. But when you copy and paste, you'll copy the line number too.
If you want a separate column, you will need to subclass QTextEdit.


Thanks a lot for your help so far, I find it really useful and instructive.
Just read the documentation, most of your questions are already answered there.
And it might be a good idea to start a new topic for different questions.

deeee
22nd May 2010, 20:33
ok, thanks for these answers.
I'm not English native so I have a few difficulties to read the documentation, sorry to bother you with my questions.
I read (though quite fast) the whole page regarding the QTextEdit class but I didn't find how to access/modify the contents of the text.

Regarding the size of the table, what I mean is that sometimes some blank zones appear, and sometimes there's a need to scroll to see the contents.
Here is my code (please tell me if/how I can make it better) :

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget *fenetre = new QWidget ();
fenetre->setFixedSize(300,600);
QTableWidget *table = new QTableWidget(3, 2, fenetre);
table->setFixedSize(400,400);
table->setEditTriggers(QAbstractItemView::NoEditTriggers) ;
for (int row = 0; row < 3; row++)
{
for (int column = 0; column < 2; column++)
{
QTableWidgetItem *item = new QTableWidgetItem();
// set the special features of each item
item->setText("item foogyfyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy yyyyyyyy");
table->setItem(row,column,item);
}
}
fenetre->show();
return a.exec();
}
If I do this :

QWidget *fenetre = new QWidget ();
fenetre->setFixedSize(300,600);
QTableWidget *table = new QTableWidget(3, 2, fenetre);
table->setFixedSize(200,200);
I get a scrollbar ;
and if I do this :

QWidget *fenetre = new QWidget ();
fenetre->setFixedSize(300,600);
QTableWidget *table = new QTableWidget(3, 2, fenetre);
table->setFixedSize(400,400);
or this

QWidget *fenetre = new QWidget ();
fenetre->setFixedSize(300,600);
QTableWidget *table = new QTableWidget(3, 2, fenetre);
//table->setFixedSize(200,200);
I get blank zones

I guessed I'd have to do a new class to make the line count appear as well.
I have no idea how big this project is though.
Can you give me a hint ? I mean, if it takes 100 code lines to implement this feature, I will drop it. Can you help me to do it please ?

Thanks.

tbscope
22nd May 2010, 20:49
ok, thanks for these answers.
I'm not English native so I have a few difficulties to read the documentation, sorry to bother you with my questions.
I read (though quite fast) the whole page regarding the QTextEdit class but I didn't find how to access/modify the contents of the text.
You're looking for these functions:
void setHtml ( const QString & text )
void setPlainText ( const QString & text )
void setText ( const QString & text )


Regarding the size of the table, what I mean is that sometimes some blank zones appear, and sometimes there's a need to scroll to see the contents.
setFixedSize should only be used in special cases.
You want to make use of a layout manager. Luckily Qt comes with a bunch of those.
Example:



#include <QGridLayout>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

QWidget *fenetre = new QWidget ();

QGridLayout *layout = new QGridLayout;

QTableWidget *table = new QTableWidget(3, 2, fenetre);
table->setEditTriggers(QAbstractItemView::NoEditTriggers) ;

layout->addWidget(table);

fenetre->setLayout(layout);

for (int row = 0; row < 3; row++)
{
for (int column = 0; column < 2; column++)
{
QTableWidgetItem *item = new QTableWidgetItem();
// set the special features of each item
item->setText("item foogyfyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy yyyyyyyy");
table->setItem(row,column,item);
}
}
fenetre->show();
return a.exec();
}


I guessed I'd have to do a new class to make the line count appear as well.
I have no idea how big this project is though.
Can you give me a hint ? I mean, if it takes 100 code lines to implement this feature, I will drop it. Can you help me to do it please ?
There's another easy way, create two qtextedits next to each other and link the scrolling.
I've seen such a widget recently, but I can't remember where.

deeee
22nd May 2010, 21:53
ok great, thanks, it works.
The layout manager seems better indeed because the blank zone is now proportional to the size of the window, which is better. But how to adapt the blank zone to the matrix and display the grey background instead ?

I see what you mean with 2 qtextedits, but how do you link the scrolling (the text scrolls down when you press enter many times as well, wouldn't that be hard to check?) ?
It would be great if you could either remember where you saw it, or help me to make it from scratch.

wysota
23rd May 2010, 08:24
This button sends a triggered signal when it is clicked on, and I want to connect it to a function called display_dock that is basically like this :
void FenPrincipale::display_dock()
{
dock.ToggleViewAction();
}
It's not how you use actions. Please read about QAction class. You just need to add toggleViewAction() to the menu or assign it to a button or wherever else you want and that's it, the action will take care of the rest.

Sorry if that has already been said, I admit I haven't read subsequent posts in this thread yet.