PDA

View Full Version : Custom widget using QT designer



GadiK
27th December 2009, 14:07
Hi,
I want to use a tab widget in my GUI. This tab widget needs to have a certain grid layout and I want to duplicate three tabs to look the same (but connect to different members of a data structure).

I understand that I need to make a custom widget. My question is whether there is a way to use the QT designer to design this custom tab widget?

If I can use the designer how do I combine the .ui file with my .ui file of the general GUI?

Thank you.

squidge
27th December 2009, 17:06
Use a QWidget and promote it to a custom class that you have designed. That way you'll tell QDesigner which header file to use for the tab and it'll do everything for you, pretty much. All you have to do is inherit QWidget in your custom class definition.

GadiK
27th December 2009, 20:50
Hi. Thank you for answering.
What I've done was placing a QTabWidget on the GUI in qt designer and then promoting it to a MyTabWidget which is derived from QTabWidget.

What bothers me is that all the widgets that I wanted to place inside the tab (labels, line edits etc.) I had to define and add manually.

I didn't understand from your answer whether there is a way to do all of the actual design inside the qt designer and not by manual labor?

Thanks

squidge
27th December 2009, 21:55
A QTabWidget contains a number of QWidgets, which themselves contain all the controls for that tab.

So when you create a new ui in designer, you create your own QWidget-derived widget, add your contrtols there, and then on your main form you have placeholders (QWidgets) which you promote to the class you created above. The end result is that on your main page, you don't see the control in the tabs, but you do when you run your app.

So one ui file will be your main app, and the other ui file will contain the controls for a tab page, which you can duplicate as much as you like.

Eg.


<widget class="QTabWidget" name="tabWidget">
<widget class="myTab" name="tab">
</widget>
<widget class="myTab" name="tab_2">
</widget>
</widget>
[...]
<customwidgets>
<customwidget>
<class>myTab</class>
<extends>QWidget</extends>
<header location="global">mytab.h</header>
</customwidget>
</customwidgets>


where mytab.h would be the header file created by Designer for your actual tab (derived from QWidget).

GadiK
28th December 2009, 08:44
OK, thank you.
Finally I got it. However, there were a couple of things that I had to overcome manually.

For instance, when I created a new gui class (VS2005 qt add-in) whose base class was QTabWidget the new ui in the qt designer was blank white and didn't accept any items.

I decided to follow your instruction word for word and created a gui class whose base class was QWidget. The ui was cooperative and placed some items on it. After that I created a QTabWidget on my main ui and promoted it to the new (QWidget based) class I had created.

When I compiled the solution I had errors (in the generated header file) regarding methods like "addTab" that weren't members of my class, which is logical since it was derived from QWidget and not QTabWidget.

I manually changed the new class's definition from "class customclass : public QWidget"
to "class customclass : public QTabWidget" and modified the constructor accordingly.

Now it works. The items I placed on the new class's gui appear inside the tab of the main ui (when I run the program).

So the only thing bothering me now is that I had to manually fix the generated code, which, to me, seems wrong.

Again, thank you for your help and if you have any comments I'd love to hear them.

Gadi.

squidge
28th December 2009, 10:41
then you are definitely doing something wrong. You don't have to write or modify a single line of code.

It seems like you are promoting the QTabWidget, rather than the tabs within it. If you want to place the entire QTabWidget into another file then thats fine (and you should derive from QTabWidget), but if you just want one of the tabs within the QTabWidget in another file (which seems to be your objective), then:

Create your tab ui with class name myTab derived from QWidget, save it. So you now have tab.ui, tab.cpp, tab.h.

Create your main form. Drop a QTabWidget onto the form. You'll notice the tabs of the QTabWidget are of type QWidget, so promote them to your myTab class.

Run the application.

GadiK
28th December 2009, 12:12
Excellent!!! It works exactly as I wanted. Thank you very much.

Now I have another issue. Lets say that during runtime I have 2 pages inside the tab widget. The pages were promoted to the custom class I made.

How do I access some widget inside the pages. I thought that I could access each page using tabWidget->widget(index).

However, when try to access a push button on the first page using tabWidget->widget(0)->myPushButton.

I get an error saying that myPushButton is not a member of QWidget.

Do I need to make tabWidget (the tab widget on the main ui) to be a class derived from QTabWidget with an overridden "widget()" function that returns a pointer to my custom class rather to a QWidget?

Thanks

squidge
28th December 2009, 12:46
The controls, such as myPushButton, will be in a private member of the class you created for the tab, and although you could make it public (or create a member function to return an appropriate pointer), you really shouldn't. Instead, you should pass a common data structure pointer to the tab class, and it will populate its own controls with that data via a member function which you create (eg. setDataSource())

Your main window class would look something like this:


QTabWidget *tabWidget;
myTab *tab;
myTab *tab_2;


So after your "ui->setupUi(this);" in your main window, you can then go "ui->tab->setDataSource(ds1);" and "ui->tab_2->setDataSource(ds2);" for example. If your tab contain 3 text edits (f.ex) then you could have a simple class which contains pointers to those (and pass a pointer to that class to your setDataSource method). If it's only a small amount of data, you could even pass it to your method directly, but that would create a more work if you wanted to extend it later on.

GadiK
28th December 2009, 12:50
I tried to figure it out myself, and from looking at the code of the ui file I think I have a solution.

If I made a custom gui class named myCustomTab then in the ui code it's presented as Ui_myCustomTab. And this class all of the items that I placed in the designer as members.

In my code, when I want to access a push button on the first page (1 of 2) of the tab widget I write this:
Ui_myCustomTab *cur_tab = (Ui_myCustomTab *) ui.tabWidget->widget(0);
cur_tab->myPushButton->setText("WORKING");

And that seems to work.

Any comments?

GadiK
28th December 2009, 14:02
First of all thank you very much for all the help so far.

Now I have several pages in the tabWidget and I'm wondering how can each page now its own index.
I've tried from within the custom widget class to access the parent and query the index like so:
QTabWidget *tab = (QTabWidget *) parentWidget();
tab->currentIndex();

But I get a runtime error.
How would you approach this?

Thank you.

squidge
28th December 2009, 14:21
I wouldn't, each tab class wouldn't care what its index was, it would only care about the data associated with itself, which it would reflect in its own controls itself, and copy any of the changed data via the gui back to the data storage. This way it's completely self-contained, and you don't need any code in the main window for handling the tabs.

However, if you prefer each class to know its index, well, the main window knows the index, so why not provide that to the tab classes? Eg. tab->setIndex(0); tab_2->setIndex(1); and then in your tab class:



public:
inline setIndex(int index) { myIndex = index; }