Subclassing QUiloader and reimplementing createWidget function of it - qt

I needed to read widget classnames, names etc from gui loaded via QUiloader.
And I got answer here that I needed to subclass QUiloader and reimplement its method.
I have MainWindow, and via menu/toolbar I load the file, and show it. And when I load I want to know what elements are in that gui to work further with them.
The code I got from a user here:
class UiLoader : public QUiLoader
{
Q_OBJECT
public:
QStringList *wlist;
UiLoader(QObject *parent = 0) : QUiLoader(parent) {}
virtual QWidget* createWidget(const QString &className, QWidget *parent =0, const QString &name = QString())
{
QWidget* widget = QUiLoader::createWidget(className, parent, name);
//here do my stuff with className, parent, name
return widget;
}
};
I used Uiloader to load my file. And it is working.
My question now is how I intercept createWidget before returning widget, I want to get the list of widget and then return Widgets.
I do not know how what is the efficient way to create a list as simple as this one:
0=>TextBox, 1=>Button, ...
I really do not care about the structure I just need to know which one comes first and what it is.
Thanks.

I wouldn't reimplement class loader at all honestly.. May be only if you need to 'inject' something into existing code which use QUiLoader a lot.. but in general only thing you need:
pWidget = ...->createWidget(...);
QList<QWidget *> widgets = pWidget->findChildren<QWidget *>();
here you go, your widgets contains list of all form components..

Related

How To Create Tri-state Actions on Menus Using Qt

I have a situation where I need a tri-state checkable action on a QMenu, and the QAction class appears to only support on or off, unless I'm overlooking something obvious. The situation I have is a context menu where multiple objects are selected, but may have different states for a given boolean condition (i.e. for a given property, some objects have a true value and some false). I can leave the action unchecked when there's a mix of values, but I feel that's misleading to the user.
I'm using Qt 5.5.1 and very experienced with Qt, but not seeing a way to achieve what I want in this instance.
There is no direct way to do it from a QAction, but it is possible to subclass the QWidgetAction and create an action that contains a QCheckBox widget.
class CheckBoxAction : public QWidgetAction {
public:
CheckBoxAction (const QString &text) : QWidgetAction(Q_NULLPTR) {
QHBoxLayout *_layout = new QHBoxLayout(Q_NULLPTR);
QWidget *_widget = new QWidget(Q_NULLPTR);
QLabel *_label = new QLabel(text);
mCheckbox = new QCheckBox(Q_NULLPTR);
_label->setAlignment(Qt::AlignLeft);
_layout->addWidget(mCheckbox);
_layout->addWidget(_label);
_layout->addStretch();
_widget->setLayout(_layout);
setDefaultWidget(_widget);
}
QCheckBox *checkbox() {
return mCheckbox;
}
private:
QCheckBox *mCheckbox;
};
Simply use the class to then add to your menu; for instance:
CheckBoxAction *checkAction = new CheckBoxAction(QStringLiteral("My Action"));
checkAction->checkbox()->setCheckState(Qt::PartiallyChecked);
menu->addAction(checkAction);
You can use the checkbox() method in order to connect to signals when it changes; or change the checkbox state. Hope this helps.

Proper way to manually set the layout of a window in Qt

I need a QMainWindow layout to change depending on the number of cores.
Therefore I set it manually (not using the Design mode).
My question is:
After this layout was created, how can I refer to the widgets it contains?
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//...
buildLayout();
//...
// Now I'd like to use something like this:
// ui->threadingTable->...
// However, it's not the member of ui
}
void MainWindow::buildLayout()
{
QWidget *window = new QWidget(this);
QTableView *threadingTable = new QTableView(window);
//...
QGridLayout *layout = new QGridLayout(window);
layout->addWidget(threadingTable, 0, 0);
//...
window->setLayout(layout);
this->setCentralWidget(window);
}
I can get the QLayoutItem out of this->centralWidget().
Or I can make all widgets in layout members of MainWindow class and access them directly.
However, I feel that neither of these is the right way.
Is there a way to pass the widgets to ui?
So that I could access them by calling
ui->threadingTable
Both options are fine. It is possible to get pointer to threadingTable from the main class member or directly from the objects hierarchy:
qDebug() << qobject_cast<QGridLayout *>(this->centralWidget()->layout())->itemAtPosition(0, 0)->widget();
qDebug() << this->centralWidget()->layout()->itemAt(0)->widget();
Of course, null verification may be required. You can also check this question QGridLayout: Getting the list of QWidget added.
The class Ui::MainWindow is automatically generated from the .ui xml form that can be generated in the Design mode: "Using a Designer UI File in Your Application"
Since the layout is constructed manually the .ui file and the ui instance is not needed at all. You can remove them from your project.
On the other hand, it is possible to use custom widgets even in the Design mode in .ui forms.
So, if you need some tricky object you can build the entire form in handy Design mode and then, for example, the standard QTableView may be promoted to your CustomTableView that is inherited from QTableView. That custom class may implement some special behavior.

Tabbed Dialog Box using Qt Designer

I'm new to Qt and having a problem with the TabbedDialog box designed using the Qt Designer.
I have a Dialog dlg on which i have placed a tabWidget MyTabWidget containing two tabs Tab1 and Tab2. I want to make separate cpp files for each tab and define the functions in their respective files. the problem i'm having is how to access the UI widgets of the dialog dlg in these respective files.
There are a few steps to be taken here which is well-explained in the following documentation.
1) Include #include "ui_foo.h"
This is necessary to access the UI elements in your code. This is the file that is available through the QtDesigner and ui compiler, aka. uic process.
2) Either inherit Ui::Foo or have an object with composition with it within your class. It would be something like:
class Foo : public QWidget
{
Q_OBJECT
public:
Foo(QWidget *parent = 0);
private:
Ui::Foo ui;
};
or
class Foo : public QWidget, private Ui::Foo
{
Q_OBJECT
public:
Foo(QWidget *parent = 0);
};
3) Then you can use this instance to access the widgets (something like ui->foo) created by the QtDesigner application.
bool Foo::doStuff()
{
ui->foo()->doStuff();
}
You probably do not wish to have two separate source files and classes as you wrote, but if you wish, the above steps could be applied for both.
That being said, I think it is better if you go through the aforementioned documentation because it is lot more detailed about the several approaches, and how to access the UI components in your source code generated by QtDesigner.
You can pass a tab pointer to your function you want to use. Something like:
void Class1::yourFunction1(QWidget *tab1);
void Class2::yourFunction2(QWidget *tab2);
You can access these widget tabs like:
ui->tab
if it was created in QtDesigner.

How to build a simple custom widget with Qt?

How to build a simple custom widget with Qt? The widget is very simple with just 2 line edit QLineEdit' in a vertical box layoutQVBoxLayout`. How to do it? I read Qt's examples on custom widget generation. They reimplement paint event to rendering the custom widget. However, mine is so simple that I cannot find a solution in Qt's reference.
Well to do it all programatically it would look something like this:
class MyWidget : public QWidget {
public:
MyWidget(QWidget *parent=0) : QWidget(parent) {
QVboxLayout *layout = new QVboxLayout();
setLayout(layout);
layout->addWidget(new QLineEdit());
layout->addWidget(new QLineEdit());
}
};
Depending on your needs you could make the line edits member variables and manipulate them as you see fit.

How can I add another tab that looks exactly like the first one (like in a browser)?

I have a browser made in Qt and a I have a tabwidget with one tab (which has a label, lineedit and a webview). I want to add others that look like the first one (have label, lineedit and webview).
How can I do this?
I don't know of any way to "clone" or duplicate an existing tab or widget, so I believe you'll need to code the tab contents yourself (i.e. not through the designer).
If all you need are a QLabel, a QLineEdit and a QWebView, that's not very complex. The idea would be to:
create a custom widget (inheriting from QWidget directly, or from QFrame)
lay out the contained widgets in the fashion you want in its constructor
add as many tabs as you want, when you want them, via the QTabWidget.addTab function.
The Tab Dialog example has everything you need - it's actually more complex than what you need because it uses different widgets for each tab. You can get away with a single widget.
If you wonder how to do the layout, and you're satisfied with what you got from the designer, you can inspect the generated (.moc) files. You'll see what layouts it uses, and you can replicate that in your own code.
Skeleton widget:
class BrowserTab : public QWidet
{
Q_OBJECT
public:
BrowserTab(QUrl const& home, QWidget *parent = 0);
void setUrl(QUrl const& url);
private:
QWebView *web;
QLabel *title;
QLineEdit *urlEdit;
};
BrowserTab::BrowserTab(QUrl const& home, QWidget *parent)
: QWidget(parent)
{
urlEdit = new QLineEdit(this);
title = new QLabel(this);
web = new QWebView(this);
QVBoxLayout *vl = new QVBoxLayout;
vl->addLayout(title);
vl->addLayout(urlEdit);
vl->addLayout(web);
setLayout(vl);
setUrl(home);
}
void BrowserTab::setUrl(QUrl const& url)
{
web->load(url);
// update label & urlEdit here
}
You'll need to do a bit more to make it a proper browser (setUrl should probably be a slot too), but this should get you started.

Resources