how can I have more than a UI for a QMainWindow? - qt

I would like to have a QMainWindow that can change it's look at runtime, i.e when a user clicks a button. Besides keeping references to different UI classes generated by the QtDesigner, is there another way of doing that? Maybe by storing each UI in a layout ? What do you think ?

How much of the main window do you want to change? You could use a QStackWidget any place you want to change things, and change the shown page of the widget when the button is pressed. This will be quick to change, but for large or complicated UIs it may be slightly slower at startup, since it will be creating the widgets for both UIs at the same time. (There are fairly easy ways to change this, also, but they do add complications to something that could be straightforward for most people.) Also, if both layouts should have the same data, just in different places, you have the additional overhead of keeping both sets of UIs up to date while the program is running.

I think I got it now.
You have a QMainWindow and when a certain event is triggered you want to change the appearance of that particular window, like remove some buttons, add a treeview widget or what not.
Well the straight forward approach would be to do it manually, remove some widgets and add new ones using regular C++ code. This can be abit hard if you're used to Qt Designer.
The other way I can think of is using Qt Designer to generate the code for the other appearances and copy it to a special function. The code generated by Qt Designer is usually in a header file called "ui_classname.h" and isn't hard to understand. You will however need to remove some of it as not all would be necessary.
Also, instead of copying the generated code from Qt Designer you could just call it. Usually your widget has a pointer to the generated class and in your widget's constructor you see something like this:
MyWindow::MyWindow(QWidget *parent) : QMainWindow(parent), m_ui(new Ui::MyWindow)
{
m_ui->setupUi(this);
}
and in the corresponding header file:
class MyWindow : public QMainWindow {
...
private:
Ui::MyWindow *m_ui;
};
You could add the additional generated classes for the other appearances and use them when your event triggers.
It might look like this:
class MyWindow : public QMainWindow {
...
private:
void changeAppearance(int id);
Ui::MyWindow *m_ui;
Ui::MyWindowFirstAppearance *m_uiFirst;
Ui::MyWindowSecondAppearance *m_uiSecond;
...
};
void MyWindow::changeAppearance(int id)
{
// some code to remove the current appearance, basically the opposite of what setupUi is doing
if (id == 0)
m_ui->setupUi(this);
else...
m_uiFirst->setupUi(this);
...
}
This has the benefit of using the generated classes directly, so every change you do in Qt Designer doesn't require a change to your main window. The problem is I'm not sure if it's legal to call setupUi more than once and in a place other than your widget's constructor, so you'll have to check that (by looking at what's happening in the setupUi function).

You can dynamically load UI layouts at runtime. Check Qt documentation for QUiLoader class.
This also enables you to upgrade UI layouts without modifying a single line of code.

What I do is to design two UIs under two different QFrames, put the two QFrames in a layout together in the QMainWindow, and then hide() and show() the correct QFrame that you want...

You can use a QTabWidget and hide its buttons. You can then design each GUI in a separate window of the tabWidget. It has the advantage over hiding frames that you won't clutter up your Qt Creator window.

If I'm getting this right, I think you might want to take a loot at style sheets. It allows you to have "skins" for your widgets, much like CSS.
If I didn't get this right, and what you're trying to do is generate .ui files on the fly and create widgets with those using QUiLoader, then you're probably going at this the wrong way since I can't think of a good reason a regular application would need that.

Related

Is is possible to edit an individual Widget in the QtDesginer?

I got a external library, which includes a derived class from QGLWidget, very similar to that one here. In that library I have a class:
class PictureGLWidget : public QGLWidget { //.. }
This extends Qt's native QGLWidget and personalizes it. But it was not written by me, I just got it, via a *.dll. So then, I bind that Widget manually in my code to a layout like:
QGridLayout* layout = new QGridLayout;
layout->addWidget(myPictureGLWidget, 0, 1);
ui->verticalLayout_5->addLayout(layout);
since I designed my MainWindowWidget with the integrated QtDesigner, which is by the way very comfortable, I would like to handle my myPictureGLWidget also in the QtDesigner, since I am currently redesigning the MainWindow.
Is there a way doing that? Thnx in advance!
Qt Designer supports any foreign widget class without needing to provide plugins for that. You only have to accept that the widget's properties and appearance won't be available within Designer.
Insert a dummy QWidget into the layout.
Right click on the widget, select "Promote to...".
Add PictureGLWidget as a new class promoted from QWidget. Specify appropriate header files etc.
Promote your widget to PictureGLWidget.
When this is done, the code generated by uic will instantiate a PictureGLWidget where you need it, instead of a dummy QWidget.
If you want to use the PictureGLWidget in the designer instead of a dummy widget, you can write a designer plugin that wraps the widget and exposes it in the widget pallette, provides property support, etc.
I might have misunderstood your question but don't you just add a QGLWidget to your design in Designer. Right click the widget and select Promote to... ?

Docking with QWinWidget: Adding DockWidgetAreas to QWidgets

I have an application utilizing QWinWidget in a Win32 window. I'd like to add DockWidgets and the associated behaviour to it. There don't seem to be any exposed APIs for adding custom DockAreas, and the latest docs are sparse beyond adding DockWidgets to a QMainWindow. Older docs imply there once was a public QDockArea class.
So far, my best option appears to be adding a neutered QMainWindow (no top-level status, no frame, etc.) to the QWinWidget and going from there (second source).
I was hoping there was a way to add DockAreas to any container, but it doesn't appear that way. As a side note, QWinWidget is used to have window manager control with our custom frame requirement, but if there's a pure QMainWindow/QWidget way to have the same result (with Qt::FramelessWindowHint), I'd be happy to switch over.
As I said in the comments, I've added within my QWinWidget in my Win32 window a QMainWindow field. That is:
class QWinWidget : public QWidget
{
...
QMainWidget* mainWidget;
}
QWinWidget::QWinWidget()
{
mainWidget = new QMainWindow(this);
mainWidget->setWindowFlags(Qt::Widget); //1
}
Note that while the docs and some forum posts (from this post) indicate you need to set window flags explicitly due to the QMainWindow constructor setting Qt::Window, I tested it without the setWindowFlags() line (marked with //1 above) without noticing anything wrong.
So, this gives me the nice QWinWidget window I spent so much time making, inside a frameless Win32 window, with a QMainWindow child and all the features that brings along with it. Docking, menu bar, status bar, etc.

How can I customize the appearance of the actions in my QToolBar?

I have just changed some toolbars from Q3ToolBars (with QToolButtons explicitly added to them) into Q4 toolbars (with actions added to them straight away instead.)
The old tool buttons had a nice outline around them, but this is not displayed in the new version; the QActions in the Q4 toolbar just look like a line of icons. Is there a way to change the 'button' style in the new version (assuming these actions can be considered as such) and give them the outline? I've looked through the QToolBar reference, but the toolButtonStyle() function only appears to work with whether you want to display icon, text, etc.
...Or will I have to just make actual tool buttons and/or QPushButtons and use addWidget()?
The widget associated with a given action is accessible through QToolBar::widgetForAction (since Qt 4.2). So, you can pass your actions to this method, get the QWidgets returned by it, convert them to QToolBar, and handle them like you normally would (code not tested):
// ...
auto toolButton =
static_cast<QToolButton *>(
m_ui.toolbar->widgetForAction(m_ui.my_Action));
// Will make the toolButton always appear raised:
toolButton->setAutoRaise(false);
// ...
As far as I've been testing, some methods might not work (i.e., QWidget::hide), so do your own testing.
Yes, of course you can edit look of QToolButtons in two different ways:
You can set it style sheet using void QWidget::setStyleSheet(const QString &)
You can reimplement QToolButtons class with new paintEvent function where you will be able to exactly set how your button should looks like.

How to use subclassed class in qt

I've subclassed qt's pushbutton and now I would like to use it in my project (instead of qpushbutton) - the problem I have is that even if I add #include "mybutton.h" in ui_class it gets overwritten and I don't know what else can I do it.
Is there a way to have this button within designer on a panel just like the ordinary qpushbutton is?
Never modify the ui_Class file yourself. Any change you make there will be overwritten when the .ui gets compiled. Instead use the promote to functionality within QtDesigner.
If some forms must be designed, but certain custom widgets are
unavailble to the designer, we can substitute similar widgets to
represent the missing widgets. For example, we might represent
instances of a custom push button class, MyPushButton, with instances
of QPushButton and promote these to MyPushButton so that uic generates
suitable code for this missing class.

How to subclass a widget to add more elements to it?

I'm trying to make a subclass of QTableView that has an embedded QLineEdit at the top for filtering the results as-you-type. I need my table to have the same API as a normal QTableView, so I want to subclass it rather than subclassing QWidget and adding a QLineEdit and QTableView to it.
I thought I could just re-implement paintEvent(QPaintEvent*), alter the QPaintEvent's rect() to start a bit lower (the height of a QLineEdit, so it draws under it) and then pass it thru to QTableView::paintEvent(), but the QPaintEvent argument only dictates what region needs to be repainted, not the region where the widget should be painted.
Anything you do in this regard is going to be hacky and result in just as much work (probably more work) as manually mapping all of the signals and slots to a child widget. You'll need to do a lot more than just change the paint events, you'd also have to adjust all of the mouse events, adjust any update rectangles, etc.
Alternatively you could just take the QTableView class from the Qt source and modify it directly (though that will probably break the LGPL and require you to publish your source if you don't have a commercial license.) But the easiest clean method is going to be implementing a container widget with the QTableView as a child.
I would try overriding the paintEvent, changing the widget::pos to be abit lower than it is and call QTableView::paintEvent()
I have to agree with Daniel: I don't think this is the right approach. You will likely want to create a custom widget with a line edit for performing the filtering. Otherwise, you will be entering into the challenging world of Qt hacking.
If you really need to provide access to the QTableView interface then simply add a public get method that returns a reference to the table.
This is somewhat similar to how Qt provides a QTabWidget class that inherits QWidget but has a private QTabBar that it uses internally. One significant difference is that it provides a protected tabBar() accessor rather than a public one.

Resources