Is there any way to setTabOrder in QMessageBox without subclassing it or writing my own? In cases when you already got big project - this might be useful.
Is there any way to setTabOrder in QMessageBox without subclassing it
or writing my own? In cases when you already got big project - this
might be useful.
There is a way to use setTabOrder in QMessageBox. All you need is QWidget* pointers to 'from' and 'to' tabs.
class MyApp
{
// ...
void tabOrdering();
QMessagebox* m_pMsgBox;
}
void MyApp::tabOrdering()
{
auto* pSaveBn = m_pMsgBox->addButton(QMessagebox::Save);
m_pMsgBox->setTabOrder(m_pMsgBox->defaultButton(), pSaveBn);
}
You may also consider using QObject::findChild method for finding tab widget stops.
Related
I am new to Qt and I want to try to understand it better.
I know from an inheritance perspective that a QMainWindow is derived from QObject. (Directly/Indirectly)
This allows for us to connect signals to slots in the following ways within the QMainWindow:
`
1- QObject::connect(sender, &QObject::signal, this, &MyObject::slot);
2- connect(sender, &QObject::signal, this, &MyObject::slot);
`
Even tough both ways are a possibility, I never understood what the major differences between them are.
Here are my questions:
1- Which method is more performant and why?
2- Why do programmers sometimes use one over the other?
I used both of these methods and they both seem to work similarly.
Consider following code.
class Foo {
static void fn();
};
class Bar: public Foo {
void bar() {
// 1
}
};
void main() {
// 2
}
If you want to call Foo::fn() at 1, you can just write fn(); since static functions is "visible" inside methods in derived classes, you can also write Foo::fn() and it will do exactly the same. If you want to call it at 2, you can only use full name Foo::fn().
In QML you can use Animator type to "animate on the scene graph's rendering thread even when the UI thread is blocked."
How can I achieve the same thing for Qt Widgets?
Basically, I want something like:
1) start loading screen / splash-screen
2) start GUI-blocking operation
3) stop loading screen / splash-screen
It is not possible to move the ui-blocking operation to a separate thread (Widgets are being created). I cannot modify this part.
I tried QQuickWidget and QQuickView containing the splash-screen scene with an Animator inside but it didn't work - they got blocked as well.
EDIT: In the separate thread I read the file containing the UI description. Then I recursively create hundreds of Widgets (including QQuickWidgets, QLabels for images, Web views etc.).
Point of the question was to see if there is a "workaround" for that (e.g. displaying the aforementioned QML scene in some separate window with an own event loop). Unfortunately at this point not much more can be done about the overall design of the above.
Probably the widgets you're creating do too much work. You have to specify exactly how many widgets you're creating, and how. Show some example code. In general, the GUI thread is for cooperative multitasking - if you have something that "blocks", break it down into tiny chunks. For example, suppose that you're processing some XML or json file to build the UI. You could have that task do it one widget at a time, and be invoked each time the event loop is about to block (i.e. use a zero-duration "timer" and invert control).
You should also do the maximum possible amount of work outside of the gui thread. I.e. the UI description should be read and converted to an efficient representation that encapsulates the work to be done in the main thread. This conversion has to be done asynchronously.
The simplest way to accomplish that is to encapsulate each widget's creation in a lambda that refers to some context object. Such a lambda would have the signature [...](BatchContext &ctx). The vector of those lambdas would be kept by the CreationContext object as well:
class BatchContext : public QObject {
Q_OBJECT
public:
using Op = std::function<void(CreationContext &)>;
using QObject::QObject;
// useful for Op to keep track of where things go
void push(QWidget *w) { m_stack.push_back(w); }
QWidget *pop() { return m_stack.isEmpty() ? nullptr : m_stack.takeLast(); }
QWidget *top() const { return m_stack.isEmpty() ? nullptr : m_stack.last(); }
int stackSize() const { return m_stack.size(); }
bool stackEmpty() const { return m_stack.isEmpty(); }
Q_SLOT void startExec() {
if (m_execIndex < ops.size())
m_execTimer.start(0, this);
}
template <typename F>
void addOp(F &&op) { m_ops.push_back(std::forward<F>(op)); }
...
private:
QVector<Op> m_ops;
QVector<QWidget *> m_stack;
QBasicTimer m_execTimer;
int m_execIndex = 0;
void timerEvent(QTimerEvent *ev) override {
if (ev->timerId() == m_execTimer.timerId())
if (!exec())
m_execTimer.stop();
}
/// Does a unit of work, returns true if more work is available
bool exec() {
if (m_execIndex < m_ops.size())
m_ops.at(m_execIndex++)(*this);
return m_execIndex < ops.size();
}
};
After the context is created asynchronously, it can be passed to the main thread where you can then invoke startExec() and the widgets will be created one-at-a-time. The stack is but an example of how you might implement one aspect of widget creation process - the tracking of what widget is the "current parent".
This question already has answers here:
Get index of QPushButton on 2D array QPushButton
(2 answers)
Closed 5 years ago.
I created a signal, which is emitted when the user input something(a number) in a qlineedit field, the signal is emitted with a parametre(the number that the user just type in the field). And i would like to use that parametre as a regular number(in a variable). Im trying to add that signal parametre to another number, and i had an error "s1 is not declared". Here is my class in the .h file and his implementation in the .cpp file
the.h file
class fenetre: public QWidget
{
Q_OBJECT
public:
fenetre();
public slots:
void calc();
void clearinput();
signals:
void thesecond(int s1);
private:
QPushButton *button1;
QPushButton *button2;
QPushButton *button3;
QPushButton *button4;
QPushButton *button5;
QPushButton *result0;
QPushButton *clear;
QLineEdit *input1;
//QLineEdit *inputsqrt;
//QLineEdit *input2;
//QLineEdit *result;
//QLineEdit *square;
};
the.cpp file
QObject::connect(button1,SIGNAL(clicked()),this,SLOT(calc()));
//QObject::connect(button2,SIGNAL(clicked()),this,SLOT(calc()));
//QObject::connect(button3,SIGNAL(clicked()),this,SLOT(calc()));
//QObject::connect(button4,SIGNAL(clicked()),this,SLOT(calc()));
//QObject::connect(button5,SIGNAL(clicked()),this,SLOT(calc()));
//QObject::connect(clear,SIGNAL(clicked()),this,SLOT(clearinput()));
//QObject::connect(result0,SIGNAL(clicked()),this,SLOT(calc()));
QObject::connect(result0,SIGNAL(thesecond(int)),this,SLOT(calc()));
}
void fenetre::calc()
{
QString s=input1->text();
bool ok;
if(!input1->text().isEmpty())
{
int s1=s.toInt(&ok,10);
emit thesecond(s1);
input1->clear();
}
QObject* obj=sender();
if(obj==result0)
{
int s2=s.toInt(&ok,10);
int A=s2+thesecond(s1);
input1->clear();
QString c=QString::number(A);
input1->setText(c);
}
}
Your code doesn't make sense.
calc() doesn't pass a parameter. There is no s1 for you to use in calc(). There is one you declare in the first if statement, but since it is declared in the block, it is out of scope after the block. Then you are using the signal as a function with a return type, which is kind of odd, considering the signal itself is declared with a void return type. Signals in Qt can return values, but that's extremely rarely used, and it will have to actually return a value for that to work.
QPushButton doesn't have a thesecond(int s1) signal. The last connection statement fails. You don't even check whether it does.
If we assume that in the last connection you meant to say this instead of result0, then what you end up with is a button connecting to calc() which emits a signal, connected to... calc() again!
All in all, your code is conceptually entirely wrong, and you don't seem to know what you are doing. Also, you might want to learn a bit on proper coding conventions, because that code is atrocious.
I suggest you edit the question and carefully explain what you actually want to happen, because the way it is right now, your intent is a mystery. Judging by your other questions, it definitely looks like you are getting ahead of yourself, go back and do more learning before you try to use it. You will have a very bad time with programming if you don't have a clue what you are doing. There is a huge difference between making occasional mistakes and having no idea what you are doing, the former is the scope of this site, the second isn't.
So I have a situation where I can't get a couple slots to fire in the order that I would like them to.
The basic set-up is that I have a Mainwindow with a statusbar that needs to get updated based on a signal from a child widget (SearchWidget). When the "Go" button is clicked on the child widget, I would like it to update the status bar to say "Searching..." and then perform the actual database search. However, I can only get the updateStatusBar slot to trigger AFTER the search is complete and displayed in a tablewidget. I have tried re-arranging the connections to the appropriate order, I have tried a separate function that emits the signal for the statusbar and then the signal for the search, but nothing seems to work. The search always executes first and the statusbar doesn't change until after that is complete.
I'm a newbie a this, but I'm guessing maybe the issue has something to do with the parent-child relationship between the mainwindow and the widget? Perhaps slots within the same widget are prioritized in some way? See basic code below.
Mainwindow class:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
initMembers();
initUI();
connect(searchWidget, SIGNAL(searchingStatus(QString)), this, SLOT(updateStatusBar(QString)));
}
void MainWindow::initMembers()
{
tabWidget = new QTabWidget(this);
searchWidget = new SearchWidget(this);
saleWidget = new SaleWidget(this);
statusBar = new QStatusBar();
setCentralWidget(tabWidget);
setStatusBar(statusBar);
}
void MainWindow::initUI()
{
tabWidget->addTab(searchWidget, "Search");
tabWidget->addTab(saleWidget, "Sale Data");
}
void MainWindow::updateStatusBar(QString status)
{
statusBar->showMessage(status);
}
SearchWidget class:
SearchWidget::SearchWidget(QWidget *parent) : QWidget(parent)
{
connect(goButton, SIGNAL(clicked), this, SLOT(buildQuery()));
}
void SearchWidget::buildQuery()
{
emit searchingStatus("Searching...");
//builds sql query
}
Any enlightening info would be much appreciated!
I suspect that it's not an ordering issue, but the fact that the SQL query is blocking the main GUI event loop: try inserting a call to QApplication::processEvents() after your emit searchStatus(...) call. If I'm correct, you should see the status bar update before the database search completes.
However, because you're still blocking the event loop, your GUI will still freeze while the DB call executes, which isn't great. You can eliminate this by running the query on a different thread (one of the simplest ways is via http://doc.qt.io/qt-5/qtconcurrent.html#run), but beware you then have to worry about concurrency issues (e.g., now you can click the go button lots of times in a row...).
In our target device, we run our QtE app with -qws argument. To rotate the screen, we specify "-display transformed:rot90" as the app argument and it works well.
However, we have a feature to rotate screen inside the app, so we try below API documented in QScreen:
QWSDisplay::setTransformation(QTransformedScreen::Rot90, 0);
But this API doesn't work at all. It's no error message in the console output.
Does anyone know what's going on about this API? Do we need to enable something else?
Contrary to other qt documentation, documentation for the embedded part of qt is indeed poor. After few days of fiddling with it, I finally managed to solve it.
First thing to do is to compile the library with -qt-gfx-transformed option (along with whatever you need).
Then you compile your application, and start it with the option you already used to activate the transformation driver. I actually started like this :
export QWS_DISPLAY=Transformed:Rot90:0
./app
As a test, I implemented this, to test whether the rotation works :
class X : public QObject
{
Q_OBJECT
public :
X() :
QObject()
{
QTimer *t = new QTimer( this );
connect( t, SIGNAL(timeout()), this, SLOT(OnTimerEvent()));
t->start( 2500 );
}
public slots :
inline void OnTimerEvent()
{
static int v = 0;
++v;
QWSDisplay::setTransformation(v%4);
std::cout<<v<<std::endl;
}
};
So, in the timer slot, I am changing the orientation with QWSDisplay::setTransformation function.