i want to implement a QProgressbar for a function in my GUI. I thought the process is simple but it seems not to be.
I thought i can implement the bar like this:
1- Button clicked
2- Progressbar and function start simultaneously
3- Function and Progressbar end simultaneously
What i have found when i searched is the update of this bar with a for-loop.I don't want to do so because my code is a simple function that must be run only one time.
Is it possible to do so ? Or am i misunderstanding something ? I found that the start and stop signals have to be managed with Threading. I wanted to ask here before i go and do further search.
Thanks.
I think the best practice is, using the main thread for QProgressbar or QProgressDialog and side thread for your function.
When main thread is used for your function, the UI won't be updated, even you use for-loop to setValue.
What I am doing is, create a QThread like with a signal giving out the progress:
class AThread(QThread):
progress = pyqtSignal(int)
def run(self):
for i in range(100):
self.progress.emit(i)
Then set the value of progressbar using the number in the signal
Related
I try much method i have find to do this, but no one work for me.
I have tried with qApp.processEvents() and with update() but no one work.
void GUI::startLoading(int currentFile) {
ui->progressBar->setValue(currentFile);
ui->progressBar->update();
}
currentFile is an int of the current loaded file from another function.
Here's a screenshot of de dubug that told the current value of the progress bar, but the progress bar don't increment.
Are you doing busy work in the GUI thread? Qt needs to get a chance to process events for the redraw to happen.
update() only enqueues the redraw. Note that setValue() calls update() itself. To avoid this problem, you can call QEventLoop::processEvents() from time to time (e.g. at the same place where you update the progress bar), or use a worker thread.
I am subclassing QFileDialog to try to get some custom behavior. I would like to connect to signals emitted by components of the dialog, e.g. the textEdited signal when the file name line edit is manually edited. I understand that QFileDialog emits some signals itself, but these do not cover the cases I would like to respond to.
I have two ways about this I can think of, but don't know how to implement. One is to somehow attain a reference to the component to connect to it's signal. The other would be something with event filters, but the event source is the dialog itself, so I don't know how to determine where mouse clicks or key presses occur.
Are either of these methods feasible? Or another way?
Here is one option (your first suggestion):
dialog = QFileDialog()
layout = dialog.layout()
# for i in range(layout.rowCount()):
# for j in range(layout.columnCount()):
# try:
# print i,j
# print layout.itemAtPosition(i,j).widget()
# except:
# pass
line_edit = layout.itemAtPosition(2,1).widget()
line_edit.setText('Hello Stack Overflow')
dialog.exec_()
This gives you access to the QLineEdit in the dialog, which has a bunch of signals you can connect to.
I've also included the code I used to find this widget. I just iterated over the widgets in the layout of the dialog and found the indices of the one I was after. So if you need access to anything else in the dialog, you should be able to find it pretty easily!
Downside to this method: If the layout changes in a future version of Qt, this will break. I suppose you could make the algorithm more robust by looking for widgets that are instances of QLineEdit, but there are always risks with hacky approaches like this!
I have 2 classes: one maintains some loop (at leas for 2-3 minutes; and is inherited from QObject) and another shows up a progress dialog (inherited from QDialog).
I want to start the loop as soon as the dialog is shown. My first solution was:
int DialogClass::exec()
{
QTimer::singleShot(0, LoopClassPointer, SLOT(start()));
return __super::exec();
}
There is a problem with throwing exceptions from slots. so I considered a possibility to make public slot start() just a public function. But now I don't know how to make it works well. Things like this:
int DialogClass::exec()
{
LoopClassPointer->start();
QApplication::processEvents();
return __super::exec();
}
don't help. The dialog doesn't appears.
Is there a common approach to this kind of situations?
some details, according to questions:
I have to work with system with its own styles, so we have a common approach in creating any dialogs: to inherit them from stytle class, which is inherited from QDialog.
my 'LoopClassPointer' is an exported class from separate dll (there is no UI support in it).
I have a 'start' button in main app, which connected with a slot, which creates progress dialog and 'LoopClassPointer'. at the moment I send 'LoopClassPointer' instance in the dialog and don't whant to make significant changes in the architecture.
Take a look at QtDemo->Concurrent Programming->Run function
e.g. in Qt 4.8: http://qt-project.org/doc/qt-4.8/qtconcurrent-runfunction.html
In this situation, I recommend you separate the logic of the loop from the dialog. Gui elements should always be kept separate.
It's great that your worker class is derived from QObject because that means you can start it running on a separate thread: -
QThread* m_pWorkerThread = new QThread;
Worker* m_pWorkerObject = new Worker; // assuming this object runs the loop mentioned
// Qt 5 connect syntax
connect(m_pWorkerThread, &QThread::started, m_pWorkerObject, &WorkerObject::start);
connect(m_pWorkerThread, &QThread::finished, m_pWorkerThread, &QThread::deleteThis);
m_pWorkerObject->moveToThread(m_pWorkerThread);
m_pWorkerThread->start();
If you're not familiar with using QThread, then start by reading this.
The only other thing you require is to periodically send signals from your worker object with progress of its work and connect that to a slot in the dialog, which updates its display of the progress.
MyWindow which inherits from QMainWindow. MyWindow contains a QGLWidget that displays an animation.
The problem is that the animation pauses whenever I open a menu or resize the window.
The animation is implemented by calling QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)) periodically, then calling redrawing each time the window receives the QEvent::UpdateRequest, like this:
bool MyWindow::event(QEvent *event)
{
qDebug() << event;
switch (event->type())
{
case QEvent::UpdateRequest:
render();
return true;
default:
return QMainWindow::event(event);
}
}
As seen from qDebug(), while a menu is open or the window is being resized, the window stops receiving update request events.
Is there a setting on QMainWindow/QWidget to make it continue to receive update request events? Or is there some better way to implement the animation?
Edit: I'm on Mac OS X.
This may be a Qt bug. I'll investigate.
Alas, you're way overcomplicating your code.
The postEvent should be simply replaced by this->update(). Behind the scenes it posts the event for you.
One can simply connect a QTimer instance's signal to widget, SLOT(update()). If you want to save on a QObject instance, use QBasicTimer and reimplement timerEvent as follows: void MyWidget::timerEvent(QTimerEvent* ev) { if (ev.timerId() == m_timer.timerId()) update(); }
There's no need to deal with event() reimplementation. Simply reimplement paintEvent() - that's what it's for.
Qt GUI updates are performing on MainThread. So slow gui response is reasonable, if you have many gui functionality does at same time. So generally, do not overload MaiThread with so many heavey function calls.
Probable solution to speed up your GUI response.
If PostEvent is called by your MainThread( if you are using timer from main gui thread ), instead move those to backend functionality in
a worker thread and postEvent once it has been done.
you call QCoreApplication::processEvents(), after your render(); function in MainThread.
This will help system to process all the other events that are in the event-loop before to continue
Please check, following link How to improve GUI response
Note: When creating and triggering the timer it will run within your thread by default, it wont start another thread.
Since I haven't heard any more from Kuba Ober about the possibility of this being a Qt bug, I went ahead and filed a bug report: https://bugreports.qt-project.org/browse/QTBUG-33382
I was able to partially work around the problem by calling the render() function more directly — that is, instead of sending an event, receiving the event, and having the event handler call the function. I accomplished this with a dispatch queue (but not the main dispatch queue, since that's tied to the default run loop so it has the same problem). However, working with the QGLWidget on multiple threads was difficult. After trying for a while to use the moveToThread() function to make this work, and considering other factors involved in the project, I decided to use something other than Qt to display this window.
Hi I have a problem, in my program I have several QLabel and QTextbrowser, at times, I want each of them to display something, but I want to do this through another function called NewMessage. So NewMessage will receive message from QLabel or QTextbrowser, and process them, then display it. But the problem is I don't want to have overloading function for QLabel and QTextBrowser, I want only 1 NewMessage function that can handle message pass in by either QLabel or QTextBrowser(the objects have to pass themselves in as well), how should I do that? Does it has to do with something called casting? Thank you !
I'm not sure I fully understand what you want to achieve. May be you could start by reading Qt documentation about QObject and qobject_cast :
http://doc.qt.io/qt-5/qobject.html#qobject_cast