How to read widgets from the .ui file in qt5? - qt

I am trying to get the list of widgets from a .ui files.
So here is a bit of code:
QUiLoader loader;
QFile file(fname);
file.open(QFile::ReadOnly);
QWidget *myWidget = loader.load(&file, this);
file.close();
QStringList avlb_wd = loader.availableWidgets();
QMessageBox msg;
foreach (const QString &str, avlb_wd)
{
msg.setText(str);
msg.exec();
}
But as I can see, availableWidgets() gives me all the widgets, not the ones that are in .ui file.
How can I achieve it?
Thanks forward.

Make a subclass of QUiLoader, and reimplement createWidget, createLayout and createAction (there's also createActionGroup, but it's not really supported any more, unless you manually edit the ui file).
These functions are called every time a new widget, layout or action is created by the ui loader. So just call the base-class implementation to get the created object, and then you can gather whatever information you like, before returning it.
UPDATE:
So the basic QUiLoader subclass would look like this (add other overloads as required):
class UiLoader : public QUiLoader
{
Q_OBJECT
public:
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);
// do stuff with className, name, widget, etc
return widget;
}
};

Related

QPixmap fails to load using resource

I am trying to write a library with a custom Qt icon-text label type object in it. However the icon never displays although the widget is shown (as tested by replacing the pixmap with plain text).
My CMakeLists.txt:
...
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/resources.cpp
COMMAND rcc -no-compress ${CMAKE_CURRENT_SOURCE_DIR}/src/qt/configmgr.qrc -name configmgr -o ${CMAKE_CURRENT_BINARY_DIR}/resources.cpp
DEPENDS src/qt/configmgr.qrc src/qt/info.png
)
...
add_library(ConfigMgr STATIC
...
src/qt/section_header.cpp
${CMAKE_CURRENT_BINARY_DIR}/resources.cpp
)
...
My configmgr.qrc:
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>info.png</file>
</qresource>
</RCC>
This produces a "resources.cpp" That looks like this:
static const unsigned char qt_resource_data[] = {
0x0,0x0,0x1,0x76,
0x89,
0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,
...
0x44,0xae,0x42,0x60,0x82,
};
static const unsigned char qt_resource_name[] = {
// info.png
0x0,0x8,
0x4,0xd2,0x59,0x47,
0x0,0x69,
0x0,0x6e,0x0,0x66,0x0,0x6f,0x0,0x2e,0x0,0x70,0x0,0x6e,0x0,0x67,
};
static const unsigned char qt_resource_struct[] = {
// :
0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
// :/info.png
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,
0x0,0x0,0x1,0x78,0x7d,0xe0,0x40,0x12,
};
...
Build output includes resources.cpp.o and that should be getting linked into the library.
My class header:
class SectionHeader : public QWidget
{
Q_OBJECT
public:
SectionHeader(const std::string &text, const std::string &info);
virtual ~SectionHeader();
private:
std::string m_info;
QPixmap m_icon;
};
My class constructor:
SectionHeader::SectionHeader(const std::string &text, const std::string &info)
: m_info{info},
m_icon(":/info.png")
{
QHBoxLayout *layout = new QHBoxLayout;
QLabel *label;
if (!m_info.empty()) {
label = new QLabel;
label->setPixmap(m_icon);
layout->addWidget(label);
}
label = new QLabel(text.c_str());
label->setAlignment(Qt::AlignCenter);
label->setStyleSheet("font-weight: bold; font-family: Calibre; font-size: 10pt");
layout->addWidget(label);
layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);
}
I have also tried calling load() on a QPixmap instance and it returns false.
Everything I have read, and similar code I have written before which is very similar to this, tells me that this should work. Why doesn't it?
The problem here is that I am trying to write a library.
I solved the problem by explicitly initialising the resources.
Find the generated CPP file for the resources. In my case it was resources.cpp.
Identify the name of the initialisation and cleanup functions. In my case they are:
int qInitResources_configmgr();
int qCleanupResources_configmgr();
Somewhere suitable, such as in the CPP file for your library's main class, locally declare these two functions.
Call the two functions in the appropriate place. E.g. main class constructor and destructor respectively.

How can my Dialog class know which element of the MainWindow has called it

I work with QT-Creator 4.9.1 based on Qt 5.12.3 and I am making a gui for a touch terminal. I have a stacked widget with multiple LineEdit widgets inside on different pages. The problem i have, is that my text from the keyboard should be shown inside the LineEdit of my MainWindow.
Question:
How can I determine which LineEdit called my touchkeyboard and how can i insert the pressed key inside my LineEdit in the MainWindow when my touchkeyboard dialog is modal?
Touch-Keyboard Dialog:
Example for one Stackwidget Page:
when creating QLineEdit you need set ID , Like that
#include <QLineEdit>
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
MyLineEdit(int id = 0, QWidget* parent = nullptr);
int id() const;
private:
int m_id;
};
MyLineEdit::MyLineEdit(int id, QWidget *parent)
:QLineEdit (parent)
,m_id(id)
{
}
int MyLineEdit::id() const
{
return m_id;
}
after that in the slot you can find out through id which one QLineEdit gave the signal
connect(myLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(customSlot(const QString &)));
or also use lambda expression
connect(myLineEdit, &QLineEdit::textChanged,[this](const QString & txt){
// Touch-Keyboard Dialog
});

QListWidget doesn't recognize signals from QTest::mouseDClick

I am trying to use QTest to test UI interactions with a QListWidget.
Interactions made from a simple click work fine (QTest::mouseClick()) but interactions from a double click do not (QTest::mouseDClick()).
Here is simplified code sample to reproduce the issue :
Dialog.h
class UILIBSHARED_EXPORT Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
int doubleClickCount = 0;
QString lastItemClicked = "";
QListWidget* GetListW();
private slots:
void on_listWidget_doubleClicked(const QModelIndex &index);
public:
Ui::Dialog *ui;
};
Dialog.cpp
QListWidget*Dialog::GetListW()
{
return ui->listWidget;
}
void Dialog::on_listWidget_doubleClicked(const QModelIndex &index)
{
lastItemClicked = ui->listWidget->item(index.row())->text();
++doubleClickCount;
}
And the test class :
class DoubleClickTest : public QObject
{
Q_OBJECT
public:
DoubleClickTest();
private Q_SLOTS:
void testDoubleClick();
};
void DoubleClickTest::testDoubleClick()
{
Dialog dialog;
dialog.show();
QListWidgetItem* item = dialog.GetListW()->item(1);
QRect rect = dialog.GetListW()->visualItemRect(item);
QTest::mouseDClick(dialog.GetListW()->viewport(), Qt::LeftButton, Qt::KeyboardModifiers(), rect.center());
QCOMPARE(dialog.doubleClickCount, 1);
}
I checked the dialog manually and the slot is called as expected.
I know this is an old topic but I have encountered the same behaviour with a QTreeView and have passed some hours to find a workaround, so I think it can be useful for someone else.
Using QTest, the signal doubleClicked is never emitted due to a part of code in sources of Qt I do not understand (qtreeview.cpp, line 1934 with Qt 5.12.1, or for others, in qabstractitemview.cpp line 1952). I don't know if it is a bug or not.
To avoid this strange code, I just added a call to QTest::mouseClick before the call to QTest::mouseDClick with the same parameters.
It worked for me because my QTreeView do nothing particular on a simple click, but it can distort tests in another case.
If anyone has a better solution I take it !

Application crashes when adding QWidget obtained from shared library to QTabWidget

//the subclass of widget in shared library
class MYWIDGETSHARED_EXPORT MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget *parent = 0);
void do_something();
};
extern "C"{
MYWIDGETSHARED_EXPORT MyWidget *getMyWidget(){ return new MyWidget;}
}
//the application which will use the shared library
void MainWindow::creatCentralWidget()
{
QTabWidget *tabWidget = new QTabWidget(this);
QLibrary myLib("xxx/MyWidget.dll");
if(myLib.load()){
MyWidget *widget = (MyWidget*)myLib.resolve("getMyWidget");
tabWidget->addTab(widget,"MyWidget");//Here cause crash!
}
//.......do_something()......
}
When I add MyWidget to tabWidget, the application crashed with code 255.
I have set the LIBS, INCLUDEPATH, DEPENDPATH, it seems no problem with them.
So I want to know, how can I correctly embed the widget from a shared library into QTabWidget? Thank you!
You have undefined behaviour due to your use of the following cast...
MyWidget *widget = (MyWidget*)myLib.resolve("getMyWidget");
The correct type for getMyWidget is...
MyWidget *(*)()
You need to resolve the symbol and then invoke it...
typedef MyWidget *(*get_my_widget_type)();
if (get_my_widget_type get_my_widget = get_my_widget_type(myLib.resolve("getMyWidget"))) {
MyWidget *widget = get_my_widget();
tabWidget->addTab(widget, "MyWidget");
}

How to pass data from one form to another in Qt?

How can I pass data from one form to another in Qt?
I have created a QWidgetProgect -> QtGuiApplication, I have two forms currently. Now I want to pass data from one form to another.
How can I achieve that ?
Thanks.
Here are some options that you might want to try:
If one form owns the other, you can just make a method in the other and call it
You can use Qt's Signals and slots mechanism, make a signal in the form with the textbox, and connect it to a slot you make in the other form (you could also connect it with the textbox's textChanged or textEdited signal)
Example with Signals and Slots:
Let's assume that you have two windows: FirstForm and SecondForm. FirstForm has a QLineEdit on its UI, named myTextEdit and SecondForm has a QListWidget on its UI, named myListWidget.
I'm also assuming that you create both of the windows in the main() function of your application.
firstform.h:
class FistForm : public QMainWindow
{
...
private slots:
void onTextBoxReturnPressed();
signals:
void newTextEntered(const QString &text);
};
firstform.cpp
// Constructor:
FistForm::FirstForm()
{
// Connecting the textbox's returnPressed() signal so that
// we can react to it
connect(ui->myTextEdit, SIGNAL(returnPressed),
this, SIGNAL(onTextBoxReturnPressed()));
}
void FirstForm::onTextBoxReturnPressed()
{
// Emitting a signal with the new text
emit this->newTextEntered(ui->myTextEdit->text());
}
secondform.h
class SecondForm : public QMainWindow
{
...
public slots:
void onNewTextEntered(const QString &text);
};
secondform.cpp
void SecondForm::onNewTextEntered(const QString &text)
{
// Adding a new item to the list widget
ui->myListWidget->addItem(text);
}
main.cpp
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// Instantiating the forms
FirstForm first;
SecondForm second;
// Connecting the signal we created in the first form
// with the slot created in the second form
QObject::connect(&first, SIGNAL(newTextEntered(const QString&)),
&second, SLOT(onNewTextEntered(const QString&)));
// Showing them
first.show();
second.show();
return app.exec();
}
You could also use pointers to access the QTextEdit (assuming that's what you're using) from the other form.
Following from Venemo's example (where FirstForm has the QTextEdit and SecondForm's the one you need to access the QTextEdit from):
firstform.h:
class FistForm : public QMainWindow
{
...
public:
QTextEdit* textEdit();
};
firstform.cpp:
QTextEdit* FirstForm::textEdit()
{
return ui->myTextEdit;
}
You can then access the QTextEdit's text in SecondForm with something like this (assuming your instance of FirstForm is called firstForm):
void SecondForm::processText()
{
QString text = firstForm->textEdit()->toPlainText();
// do something with the text
}

Resources