PDA

View Full Version : QScrollArea layout is correct with debug message. Remove debugging results in error.



Debra
12th June 2019, 21:35
I am using Qt 5.9.1 on an Oracle virtual box 6.0 emulating a linux box. The MySQL database is MariaDB.
I am trying to display user information on a QScrollArea and I have up and down buttons to jump back and forth between users instead of displaying the vertical scrollbar. When the first user is displayed, the up button should be disabled since there is no other users before of the current user. When the last user is displayed, the down button should be disabled since there is no other users after the current user. For debugging purposes, I added a QMessageBox::information and everything works fine. If I remove the QMessageBox, the buttons do not set their enabled property to false.

In the constructor, the signals are attached to the slots:


connect(ui_previous_user_pushButton, SIGNAL(clicked()), this, SLOT(SlotUserUp()));
connect(ui_next_user_pushButton, SIGNAL(clicked()), this, SLOT(SlotUserDown()));
connect(ui_scrollArea->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(SlotUserPositionChanged(int)));


For each user, the following is added to the QScrollArea:


QFrame* layout_frame = new QFrame(this);
QHBoxLayout* h_box_layout = new QHBoxLayout();
h_box_layout->addStretch();
QFrame* user_frame = new QFrame(this);
...
QGridLayout* frame_layout = new QGridLayout();
...
user_frame->setObjectName("user_frame");
QLabel* user_label = new QLabel(QString(tr("Operator : %1")).arg(user->GetName()), this);
...
// Add widgets to frame layout
frame_layout->addWidget(user_label, 0,0,1,6,Qt::AlignLeft);
...
user_frame->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
user_frame->setLayout(frame_layout);
hbox_layout->addWidget(user_frame);
h_box_layout->addStretch();
layout_frame->setLayout(h_box_layout);
main_layout->addWidget(layout_frame);
...


I then create a list of the user frames. m_user_list is a private member variable of type QList<QFrame*>. The list contains 4 widgets on the database I am using, the min Y value is 9 and the max Y value is 1213. As you will find, I tried to process the events, since it seems like a repaint problem:


m_user_list = ui_scrollArea->findChildren<QFrame *>(QString("user_frame"),Qt::FindChildrenRecursively);
if (!m_user_list.isEmpty())
{
//QMessageBox::information(0, "Empty?", "No");
qApp->processEvents();
int min = m_user_list.at(0)->parentWidget()->y(); // The minimum possible Y value of a user frame.
int max = 0; // The maximum possible Y value of a user frame.
for (int = 0; i< m_user_list.size(0; i++)
{
if (min > m_user_list.at(i)->parentWidget()->y())
{
min = m_user_list.at(i)->parentWidget()->y();
}
if (max < m_user_list.at(i)->parentWidget()->y())
{
max = m_user_list.at(i)->parentWidget()->y();
}
}
QMessageBox::information(0,"Min/Max",QString("Min: %1, Max: %2").arg(min).arg(max));
qApp->processEvents();
ui_scrollArea->verticalScrollBar()->setMinimum(min);
ui_scrollArea->verticalScrollBar()->setMaximum(max);
// ui_scrollArea->verticalScrollBar()->setSliderPosition(min);
ui_scrollArea->verticalScrollBar()->setValue(min);
qApp->processEvents();
}
...


The up button click is connected to the following code:


void OD:SlotUserUp(void)
{
int difference = INT_MAX; // The difference between the scrollbar value and a previous user.
int closest_index = 0; // The index in the list of the closest label of a previous user.
if (!m_user_list.isEmpty())
{
for(int i=0; i<m_user_list.size(); i++)
{
if (m_user_list.at(i)->parentWidget()->y() < ui_scrollArea->verticalScrollBar()->value())
{
if (difference > (ui_scrollArea->verticalScrollBar()->value() - m_user_list.at(i)->parentWidget()->y()))
{
difference = (ui_scrollArea->verticalScrollBar()->value() - m_user_list.at(i)->parentWidget()->y());
closest_index = i;
}
}
}
ui_scrollArea->verticalScrollBar()->setValue(m_user_list.at(closest_index)->parentWidget()->y());
}
}

I have similar code for the down button.

When the scrollbar value changes, this is the method that is run:


void OD::SlotUserPositionChanged(int position)
{
Q_UNUSED(position);
if (ui_scrollArea->verticalScrollBar()->value() == ui_scrollArea->verticalScrollBar()->minimum())
{
ui_previous_user_pushButton->setEnabled(false);
}
else
{
ui_previous_user_pushButton->setEnabled(true);
}
if (ui_scrollArea->verticalScrollBar()->value() == ui_scrollArea->verticalScrollBar()->maximum())
{
ui_next_user_pushButton->setEnabled(false);
}
else
{
ui_next_user_pushButton->setEnabled(true);
}
}


Any help will be greatly appreciated!

Debra
13th June 2019, 16:59
The setting of the minimum and maximum is where the problem is.


// QMessageBox::information(0,"Min/Max",QString("Min: %1, Max: %2").arg(min).arg(max));
qApp->processEvents();
ui_scrollArea->verticalScrollBar()->setMinimum(min);
ui_scrollArea->verticalScrollBar()->setMaximum(max);
// ui_scrollArea->verticalScrollBar()->setSliderPosition(min);
ui_scrollArea->verticalScrollBar()->setValue(min);
qApp->processEvents();

Either the code is being ignored or there is something overwriting these values after I assign the calculated values. I created a non-elegant fix by saving off the min and max values to member variables and setting their values again in SlotUserPositionChanged. There should be a better way - any suggestions are welcome.
Should I be using setValue or setSliderPosition? The documentation says there is a difference with tracking, but I don't know what is meant by tracking.