How to load a widget from a ui file saved in resource? - c++

I have a .ui file saved in the .qrc named treeview.ui, into this .ui i have a QTreeView that have been promoted on Qt Designer, to a subclass called TreeView.
I'm reading this file in a loop and in each iteration copying this TreeView to a QStackedWidget, the widget is being added to the container correctly, however, I'm getting this message in the console:
"QFormBuilder was unable to create a custom widget of the class 'TreeView'; defaulting to base class 'QTreeView'."
What i'm missing?
#include "treeview.h" // The file that contains the subclass promoted on Qt Designer
QUiLoader loader;
QFile file(":/ui/treeview.ui");
//file.open(QIODevice::ReadOnly);
for (i = map.begin(); i != map.end(); ++i)
{
// ...
file.open(QIODevice::ReadOnly);
QWidget *form = loader.load(&file);
file.close();
qDebug() << form;
if (!form) {
qDebug() << "Error loading UI file:" << loader.errorString();
}
ui->treeViewContainer->addWidget(form);
}
Also, do i really need to open the file and call loader.load(&file) in each iteration of the loop to be able to make a new 'copy' of the widget in the treeViewContainer?

Related

Qt6: "Unable to read Memory" when pointing to a QLineEdit from a QFormLayout

I want to get the text from a QLineEdit, which is in a QFormLayout, to save it to a File. The saving works fine, but I am not able to get the text form the QLineEdit and when I look at it from the Debugger it says "Unable to read Memory". I canĀ“t figure out how to correctly point to the QLineEdit, so that I can get the text.
With this code I want to get the text:
QJsonArray Kegelbuch::saveSettings() {
QFormLayout* formLayout = (QFormLayout*)ui.einstellungenTab->layout();
QJsonArray data;
QLineEdit* settingsEdit;
for (int i = 0; i < formLayout->rowCount(); i++) {
settingsEdit = (QLineEdit*)formLayout->itemAt(i, QFormLayout::ItemRole::FieldRole);
}
return data;
}
How the window looks:
Replace
settingsEdit = (QLineEdit*)formLayout->itemAt(i, QFormLayout::ItemRole::FieldRole);
with
settingsEdit = (QLineEdit*)(formLayout->itemAt(i, FormLayout::ItemRole::FieldRole)->widget());
Background: itemAt() returns a QLayoutItem*, so you need to call QWidget *QLayoutItem::widget() to get the widget.

QT5 C++, Is there a way I can get the current text of a widget within a qlist container

I need to retrieve the text in the order in which they appear on the user form. I am trying as below:
QString line = "QLineEdit";
QString combo = "QComboBox";
QList<QWidget *> childWidgets = ui->frame_3->findChildren<QWidget *>();
QStringList data;
for(auto widget : childWidgets){
if(widget->metaObject()->className() == line || widget->metaObject()->className() == combo){
data.append(widget->text()); //append the text of the lineEdits and ComboBoxes to data
}
}
I get the following compile error from the above code:
"no member named 'text' in QWidget
Since you pointed out the QWidget base class does not have a text member function you will need to access the QComboBox and QLineEdit directly to get the current text.
QList<QWidget *> childWidgets = ui->frame_3->findChildren<QWidget *>();
QStringList data;
for(auto widget : childWidgets){
auto combo = dynamic_cast<QComboBox*>(widget);
if (combo) {
data << combo->currentText(); // currentText() returns the text from the combobox
}
else {
auto lineEdit = dynamic_cast<QLineEdit*>(widget);
if (lineEdit) {
data << lineEdit->text(); // A line edit has a text() member.
}
}
}
This code does not handle ordering. I believe the order is in the same order as added to the parent.

Why my C++ Qt UI got translated but not my QStrings in my program?

I needed to translate my english UI in french, so I did all the necessary with .ts and .qm files, load it in the QTranslator class, and install it to the QApplication:
//in the InterfaceWidget constructor:
QTranslator myappTranslator;
bool loaded = myappTranslator.load("myApp_" + QLocale::system().name());
qDebug() << "Is translation file loaded?" << loaded; // RETURNS TRUE
QApplication::installTranslator(&myappTranslator);
ui.setupUi(this);
ui.retranslateUi(this); //works, it translates the UI
Later, I create and attach to the InterfaceWidget another Widget (in a tab) called ConfigurationTabUI :
m_ConfigurationTabUI = new ConfigurationTabUI(ui.configTab);
The corresponding UI is also translated to french, correctly.
And here is my problem: in the ConfigurationTabUI's methods, it doesn't work when I try to translate a simple QString:
void ConfigurationTabUI::on_ValidButton_clicked(){
QString msg(ConfigurationTabUI::tr("message to translate"));
qDebug() << "translated string: " << msg; // NOT TRANSLATED
}
I really have no clue why...
Thanks for your help.
Note: I Use Qt5.2 and I double checked that the .ts file contains the right translated string.
Ok, I found the problem, it's just a dumb oversight:
QTranslator is created on the stack and not dynamically (on the heap), so the object is destroyed at the end of the method.
As a result, it translates the UI because the object is still there but later, when a slot is called, nothing get translated.
Here is my code:
//in the InterfaceWidget constructor:
QTranslator* myappTranslator = new QTranslator(QApplication::instance());
bool loaded = myappTranslator->load("myApp_" + QLocale::system().name());
qDebug() << "Is translation file loaded?" << loaded; // RETURNS TRUE
QApplication::installTranslator(myappTranslator);
ui.setupUi(this);
and in ConfigurationTabUI (which inherits from QWidget):
void ConfigurationTabUI::changeEvent(QEvent *e)
{
if (e->type() == QEvent::LanguageChange) {
ui.retranslateUi(this);
reset(); //my method to reload some data in UI
} else
QWidget::changeEvent(e);
}

using QFileSystemWatcher::Files() to get file count of watched folder example? count is always 0?

I have tried to figure this out over the weekend, but to no avail. I cant seem to find an example using QFileSystemWatcher::Files() directly so i thought i would ask.
I have a program that :
lets the user select a 'source' folder.
press a button to start watching that source folder for new files
there is a signal emitted using 'directoryChanged()' where i try to update the count every time a file is added or removed.
I will profess that my implementation of QfileSystemWatcher is probably not correct. but this code is working and does trigger the signal/slot. but the count is always zero...
from mainwindow.cpp...
the signal:
//connect push buttons
QObject::connect(ui->startButton, SIGNAL(clicked()),
this, SLOT(startButtonClicked()));
//link qfilesystemwatcher with signals and slots
QObject::connect(&hotfolder, SIGNAL(directoryChanged(QString)), this, SLOT(hotfolderChanged()));
the slots:
void MainWindow::startButtonClicked(){
//start the file system watcher using the 'source folder button'
//first, get the resulting text from the source folder button
QString sourceText = ui->sourceBtnLineEdit->text();
ui->statusbar->showMessage(sourceText);
//convert the text from source button to a standard string.
string filePath = sourceText.toStdString();
cout << filePath << endl;
//call method to add source path to qfilesystemwatcher
startWatching(sourceText);
}
void MainWindow::hotfolderChanged(){
int fileCount = filesWatched();
ui->statusbar->showMessage(QString::number(fileCount));
}
from magickWatcher.h
#ifndef MAGICKWATCHER_H
#define MAGICKWATCHER_H
#include <QFileSystemWatcher>
#include <mainwindow.h>
//create the qFileSystemWatcher
QFileSystemWatcher hotfolder;
//add folder to qfilesystemwatcher
//starts watching of folder path
int startWatching( QString folder){
hotfolder.addPath(folder);
cout << "hotfolder created!" << endl;
return 0;
}
//get file list of folder being watched
int filesWatched(){
QStringList watchedList = hotfolder.files();
//report out each line of file list
for (int i = 0; i < watchedList.size(); ++i){
cout << watchedList.at(i).toStdString() << endl;
cout << "is this looping?!!" << endl;
}
return watchedList.count();
}
#endif // MAGICKWATCHER_H
How can i use QFileSystemWatcher to get the file count of the watched folder? I know about QDir and its options but want to specifically know how to use QFileSystemWatcher.
I am still wrapping my head around c++ in general so thank you for any advice or tips as well. I think maybe my problem is how i am implementing QFileSystemWatcher.
Some relevant links i have used:
QFileSystemWatcher working only in main()
http://doc.qt.io/qt-5/qfilesystemwatcher.html#files
First let's have a closer look at docs (bold format is mine):
QFileSystemWatcher examines each path added to it. Files that have been added to the QFileSystemWatcher can be accessed using the files() function, and directories using the directories() function.
So, files() only returns a list of files which you have already added to the watcher using addPath() method, NOT a list of files implicitly being watched by adding a directory.
You can get information about files in the watched directory e.g. by using QDir::entryInfoList with filters applicable in your case. At least QDir::Files and possibly QDir::NoDotAndDotDot would make sense.
//get file list of folder being watched
int filesWatched() {
QString folder = "/path/to/hotfolder/";
QDir monitoredFolder(folder);
QFileInfoList watchedList =
monitoredFolder.entryInfoList(QDir::NoDotAndDotDot | QDir::Files);
QListIterator<QFileInfo> iterator(watchedList);
while (iterator.hasNext())
{
QFileInfo file_info = iterator.next();
qDebug() << "File path:" << file_info.absoluteFilePath();
}
return watchedList.count();
}

Removing item from QListWidget from inside a Widget

I have a QListWidget in my MainWindow that displays a list of VideoWidgets (a custom QWidget).
VideoWidget has a clickable label where on clicking the label it should delete a file and then remove the QListItem which holds the VideoWidget from the QListWidget. Here is my VideoWidget class:
VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent)
{
ClickableLabel *smallRed = new ClickableLabel(this)
//...
QObject::connect(smallRed,SIGNAL(clicked()),this,SLOT(removeVideo()));
}
void VideoWidget::removeVideo(){
//...code to remove a file
QListWidget* list = myParent->getList();
QListWidgetItem* item = list->takeItem(list->currentIndex().row());
myList->removeItemWidget(item);
}
The problem is that clicking the smallRed label will not select its item in the QListWidget which means that list->currentIndex().row() will return -1. Clicking anywhere else in the Widget does select the current item. For the code to work I currently have to first click anywhere in the VideoWidget and then click its ClickableLabel. Is there any way I can achieve the same effect with one single click on my ClickableLabel?
From your previous qestion, we suggested use signal and slots. For example:
for(int r=0;r<3;r++)
{
QListWidgetItem* lwi = new QListWidgetItem;
ui->listWidget->addItem(lwi);
QCheckBox *check = new QCheckBox(QString("checkBox%1").arg(r));
check->setObjectName("filepath");
connect(check,SIGNAL(clicked()),this,SLOT(echo()));
ui->listWidget->setItemWidget(lwi,check);
}
Slot:
void MainWindow::echo()
{
qDebug() << sender()->objectName() << "should be remmoved";
}
It is not unique way to solve this problem, but it shows all main things, with signals and slots mechanism, objectName and sender() you can achieve all what you need.
sender() return object which send signal, you can cast it, but if you need only objectName you should not cast.