QLayout and Valgrind - qt

I've been struggling with a message from Valgrind.
I'm using a QLayout taken from Qt examples (FlowLayout) and I add at runtime, when the user presses an add button, some widgets to this layout.
This is the initialitation snippet inside a constructor of my container QWidget class inherited:
// scroll area
auto* central = new QWidget();
central->setObjectName("CentralWidget");
m_layout = new FlowLayout;
ui->scrollArea_step->setFrameShape(QFrame::NoFrame);
central->setLayout(m_layout);
ui->scrollArea_step->setWidgetResizable(true);
ui->scrollArea_step->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui->scrollArea_step->setWidget(central);
I've understood that because of the setWidget(central), I don't need to assign a parent to the "central" widget.
When the user clicks the add button into the interface, the program invokes this snippet:
// create the button from rf data
ShortMenuPushButton* stepButton = _createStepButton(m_rfData);
m_layout->addWidget(stepButton);
QPushButton* deleteStepButton = _createDeleteButton();
m_layout->addWidget(deleteStepButton);
_createStepButton has this code:
auto* stepButton = new ShortMenuPushButton(this);
The same operation is done by _createDeleteButton() for the other button.
If I run Valgrind, I get the same message:
==59123== 176 bytes in 2 blocks are definitely lost in loss record 8,040 of 8,630
==59123== at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==59123== by 0x6430849: QLayoutPrivate::createWidgetItem(QLayout const*, QWidget*) (qlayout.cpp:200)
==59123== by 0x6431AA0: QLayout::addWidget(QWidget*) (qlayout.cpp:236)
==59123== by 0x7DA967: Dialogs::Dialog_multistep::onButtonAddStep_clicked() (dialog_multistep.cpp:419)
==59123== by 0x7E8B13: QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (Dialogs::Dialog_multistep::*)()>::call(void (Dialogs::Dialog_multistep::*)(), Dialogs::Dialog_multistep*, void**) (qobjectdefs_impl.h:152)
==59123== by 0x7E8A87: void QtPrivate::FunctionPointer<void (Dialogs::Dialog_multistep::*)()>::call<QtPrivate::List<>, void>(void (Dialogs::Dialog_multistep::*)(), Dialogs::Dialog_multistep*, void**) (qobjectdefs_impl.h:185)
==59123== by 0x7E89B4: QtPrivate::QSlotObject<void (Dialogs::Dialog_multistep::*)(), QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) (qobjectdefs_impl.h:414)
==59123== by 0x9284CB5: call (qobjectdefs_impl.h:394)
==59123== by 0x9284CB5: QMetaObject::activate(QObject*, int, int, void**) (qobject.cpp:3774)
==59123== by 0x64FAFF1: QAbstractButton::clicked(bool) (moc_qabstractbutton.cpp:312)
==59123== by 0x64FB1F3: QAbstractButtonPrivate::emitClicked() (qabstractbutton.cpp:414)
==59123== by 0x64FCD8D: QAbstractButtonPrivate::click() (qabstractbutton.cpp:407)
==59123== by 0x64FCEE4: QAbstractButton::mouseReleaseEvent(QMouseEvent*) (qabstractbutton.cpp:1011)
But in FlowLayout I've the distructor with:
void FlowLayout::clear()
{
QLayoutItem* item;
while ((item = takeAt(0)))
{
delete item->widget();
}
}
I do not understand where the leak is.
I appreciate any suggestion.
Thank you

I've found the problem.
As I wrote, I've used the class FlowLayout, taken from a famous example (Qt).
The method clear does:
void FlowLayout::clear()
{
QLayoutItem* item;
while ((item = takeAt(0)))
{
delete item->widget();
}
}
but the QLayoutItem return nullptr in the method QLayoutItem::widget().
Maybe because QLayoutItem is a base class and should be derived.

Related

Qt -how to get variable value from another function in same file

New to Qt. Still learning it. I have clone.ui, clone.h and clone.cpp. clone ui has 2 buttons.
Browse button-> to Selection a destination path
Add button -> Clone(copy) a file
Clone.h
QString destination_path;
QFileDialog *fdialog;
Clone.cpp has
QFileInfo finfo; // Declare outside function to increase scope
QString destination_name;
void Clone:: on_pushButton__Browse_clicked()
{
/*get the destination path in QString using QFileDialog
Got destination_path */
QString destinatino_path = QFileDialog::getExistingDirectory(....);
QFile finfo(destination_path);
// QFileDialog finfo(destionation_path)
}`
In the same file Clone.cpp
void Clone:: on_btn_Add_clicked()
{
// how to get the same destination_path value here...
//using QFile or some other way?
}
I struck here, Am i missing anything? Any thoughts/suggestion highly useful.
You've create a class (Clone) which has a data member QString destination_path.
Since it is a member variable it has class scope (as in you can access the same variable in any Clone:: member function for the same Clone object).
The problem is that you've hidden it by declaring another QString destination_path in Clone::on_pushButton__Browse_clicked().
void Clone::on_pushButton__Browse_clicked()
{
...
// this *hides* the class member with the same name
QString destination_path = QFileDialog::getExistingDirectory(....);
...
}
The solution is to remove QString from the beginning of the line, which means you are now assigning to the class object's data member.
void Clone::on_pushButton__Browse_clicked()
{
...
// now you're assigning to your object's data member
destination_path = QFileDialog::getExistingDirectory(....);
...
}
Later, in Clone::on_btn_Add_clicked() you can access destination_path, and it will have the value assigned to it in Clone::on_pushButton__Browse_clicked

Qt5 | Function w/ Slot Not Working

I've made an app with two forms.
When I press the save button in the second form, it updates the DB Record, and returns back to the first form. I've connected the two forms via Signal-Slot with this code:
DruckerData.h
signals:
void btnSavePressed(QString printerName);
DruckerData.cpp
UiMainWindow frmMain;
connect(this,SIGNAL(btnSavePressed(QString)),&frmMain,SLOT(refreshSaved( QString )));
emit btnSavePressed(ui->ledit_druckerName->text());
this->hide();
UiMainWindow.h
public slots:
void refreshSaved(QString printerName);
UiMainWindow.cpp
void UiMainWindow::refreshSaved(QString printerName){
qDebug()<<"Updated: "<<printerName;
show_list(); //<<<<<<<<<<<<<<<<<<<<<< this function
}
show_list
void UiMainWindow::show_list (){
QList<DB_Printers_lvs> list;
DB_Printers_lvsTransporter t("LVS");
QString wc;
this->setCursor(Qt::WaitCursor);
wc = QString("where 1=1 order by nam_printer");
if (!t.load_dbPrinters_lvs_wc(&list,wc))
{
log()<< "get printers failed"<< wc << t.getLastError();
this->setCursor(Qt::ArrowCursor);
return;
}
ui.treeWidget->clear();
foreach (DB_Printers_lvs db, list)
{
QTreeWidgetItem *item = new QTreeWidgetItem(0);
printer_to_qtreewidgetitem(item, db);
ui.treeWidget->insertTopLevelItem(ui.treeWidget->topLevelItemCount(), item);
}
ui.treeWidget->header()->resizeSections(QHeaderView::ResizeToContents);
ui.bow_search->apply();
this->setCursor(Qt::ArrowCursor);
}
When I press the button on the second form and the first form shows I see debug writing Updated with printer name but the problem is how can I call or start this funktion show_list()?
Thanks for help.
The problem that you create second instance of UiMainWindow here:
UiMainWindow frmMain;
Then you connect signal with this second instance, call it's slots, but you don't even show this second instance of MainForm. Instead of this, you should connect signal and slot inside the UiMainWindow just after you create DruckerData form. Unfortunatly there is no this code at your question so i can't show exactly place. This should be something like this:
//Inside UiMainWindow
DruckerData *data = new DruckerData(this);
connect(data, SIGNAL(btnSavePressed(QString)),this,SLOT(refreshSaved( QString )));
data->show();

Create a folder in runtime when date changes [duplicate]

I need to notify some objects to clear their cache at new day begins. So, I could create QTimer or something similar and check every ms that now midnight +-5ms or not, but it's not a good idea for me.
Is there(in QT) any standard mechanisms to get notified about this event without allocating any new object? Something static or living since application's initialization like qApp?
What would you do in situation like this where you need to do something at 00:00?
UPD:
I'm looking for fast enough solution. Fast means that I need to clear container in slot as quick as it possible, 'cause since midnight data in the container become invalid. So, there is some other timer which shots every 100ms for instance and it trying to get data from container. I need to clear container with invalid data right before any possible try of getting access.
The simplest solution does indeed utilize a timer. Polling for the passage of time in not only unnecessary, but would be horrible performance-wise. Simply start the actions when the midnight strikes:
static int msecsTo(const QTime & at) {
const int msecsPerDay = 24 * 60 * 60 * 1000;
int msecs = QTime::currentTime().msecsTo(at);
if (msecs < 0) msecs += msecsPerDay;
return msecs;
}
// C++11
void runAt(const std::function<void> & job, const QTime & at, Qt::TimerType type = Qt::VeryCoarseTimer) {
// Timer ownership prevents timer leak when the thread terminates.
auto timer = new QTimer(QAbstractEventDispatcher::instance());
timer->start(msecsTo(at), type);
QObject::connect(timer, &QTimer::timeout, [=job, &timer]{
job();
timer->deleteLater();
});
}
runAt([&]{ object->member(); }, QTime(...));
// C++98
void scheduleSlotAt(QObject * obj, const char * member, const QTime & at, Qt::TimerType type = Qt::VeryCoarseTimer) {
QTimer::singleShot(msecsTo(at), type, obj, member);
}
class MyObject : public QObject {
Q_OBJECT
void scheduleCleanup() {
scheduleSlotAt(this, SLOT(atMidnight()), QTime(0, 0));
}
Q_SLOT void atMidnight() {
// do some work here
...
scheduleCleanup();
}
public:
MyObject(QObject * parent = 0) : QObject(parent) {
...
scheduleCleanup();
}
};
there is some other timer which shots every 100ms for instance and it trying to get data from container.
Since both of these timers presumably run in the same thread, they execute serially and it doesn't matter how much "later" either one is. They won't both run at the same time.

QMetaObject InvokeMethod method passing integer Array argument

I am fairly new to Qt, and I am trying to do some Android Development. I am working with Qt and using the QAndroidJNIEnvironment. In the code, I am implementing my native method using QMetaObject::invokeMethod to invoke a slot in the QMainWindow header. The problem is that the native method in the java file has a parameter that is a java integer array(equivalent type I believe in QAndroindJniObject is jintArray). I can't find the corresponding c++/Qt type to place in the Q_ARG(type, value ) macro to resolve the argument. Please help me understand what I am doing wrong, as i thought the equivalent type to jintArray was int [], but I receive error when I use that. Thanks in advance for the help.
onReceiveNativeMounted (JNIEnv * env, jobject obj,jint array_index,jintArray version)
{
QMetaObject::invokeMethod(&MainWindow::instance(), "onReceiveMounted"
, Qt::QueuedConnection, Q_ARG(int, array_index),Q_ARG(int[], version));
return array_index;
}
the error i receive is below:
error: no matching function for call to
'QArgument<int []>::QArgument(const char [6], _jarray*&)'
#define Q_ARG(type, data) QArgument<type >(#type, data)
^
As requested, the java function signature is below:
public static native int onReceiveNativeMounted(int array_index, int[] version);
You need to access the java arrays according to the JNI API. The easiest thing to do is to convert the data to a QVector. You need to copy the Java array since its lifetime is not under your control (unless you wish it to be, but that makes life much harder than it needs to be).
QVector toQVector(JNIEnv * env, jintArray arr) {
auto len = (*env)->GetArrayLength(env, arr);
QVector result(len);
auto data = (*env)->GetIntArrayElements(env, arr, 0);
for (int i = 0; i < len; ++i)
result[i] = data[i];
(*env)->ReleaseIntArrayElements(env, arr, data, 0);
return result;
}
It is a bit more performant to perform the call directly from a functor, rather than through invokeMethod. The functor can capture the vector:
int onReceiveNativeMounted (JNIEnv * env, jobject obj, jint array_index, jintArray version)
{
auto window = &MainWindow::instance();
auto vector = toQVector(env, version);
QObject sig;
sig.connect(&sig, &QObject::destroyed, window, [=]{
window->onReceiveMounted(array_index, vector.data());
}, Qt::QueuedConnection);
return array_index;
}

Qt - invoking slots that take custom pointers as arguments

I'm trying to hack with Qt's signals and slots, and I ran into an issue where QMetaType::invokeMethod won't properly pass pointer arguments to the slot being called.
call(QObject *receiver, const char *slot, const QList<QGenericArgument> &args)
{
const QMetaObject *meta = receiver->metaObject();
bool success = meta->invokeMethod(receiver, slot,
args.value(0, QGenericArgument()),
args.value(1, QGenericArgument()),
args.value(2, QGenericArgument()),
...
args.value(9, QGenericArgument()));
}
Then I call it the following way:
MyReceiver *receiver;
MyObject *myObject;
call(receiver, "mySlot", QList<QGenericArgument>() << Q_ARG(MyObject *, myObject));
Where class MyObject : public QObject { ... }. I also do Q_DECLARE_METATYPE(MyObject *) and qRegisterMetaType<MyObject *>("MyObject *")
What happens is that the slot on the receiver is being invoked, but with the value of the argument is always 0 no matter what I pass to the call(...) as Q_ARG
Out of curiosity I looked into the auto-generated MOC file of the receiver, and found that the slots are invoked with the following code:
void MyReceiver::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
MyReceiver *_t = static_cast<MyReceiver *>(_o);
switch (_id) {
case 0: _t->mySlot((*reinterpret_cast< MyObject*(*)>(_a[1]))); break;
default: ;
}
}
}
Turns out that the value of _a[1] bears proper address of MyObject *. But the reinterpret_cast turns it into 0.
Now I have the following questions:
1) How to programmatically invoke a slot and make sure that the pointer arguments are properly passed to the slot?
2) What does this *reinterpret_cast< MyObject*(*)>(_a[1]) mean? What the extra parentheses (*) mean, and how to interpret this piece of code?
Ok, I think I figured why it's not working... Q_ARG only will create a pointer to my pointer and store the former. I didn't mention that the call function was part of the Task call meant to invoke a slot later on - when the values wrapped into Q_ARG are already out of scope. Basically Q_ARG only maintains a weak reference to the argument object.

Resources