In the function - loadData(), First, show the dialog with QProgressBar,and then, call setValue() for the progressbar base on the business. when the value of progressbar increase to 100%, hide the dialog and set the value to 0.
My question is:
When I enter the loadData() function again, after exec the dlgo->show(), the value of progressbar isn't start from 0, but jump from 100 to 0, and then go on.
What can I do to make the value of progressbar start from 0 when I tried show the dialog again?
Thank you!
void loadData() {
mProcessBarDlg->show();
{
mProcessBarDlg->ui.progressBar->setValue(XX);
}
mProcessBarDlg->hide();
mProcessBarDlg->ui.progressBar->setValue(0);
}
Set it to zero before you show it.
EDIT:
The following code, derived from the poster's question, works:
#include <qapplication.h>
#include <qdialog.h>
#include <qprogressbar.h>
QDialog *mProcessBarDlg;
QProgressBar *progressBar;
void loadData() {
mProcessBarDlg->setValue(0);
mProcessBarDlg->show();
for (int i = 0; i < 100000000; ++i){
if (i % 100 == 0){
qApp->processEvents();
}
}
{
progressBar->setValue(50);
for (int i = 0; i < 100000000; ++i){
if (i % 100 == 0){
qApp->processEvents();
}
}
}
mProcessBarDlg->hide();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
mProcessBarDlg = new QDialog;
progressBar = new QProgressBar(mProcessBarDlg);
loadData();
for (int i = 0; i < 100000000; ++i){
if (i % 100 == 0){
a.processEvents();
}
}
loadData();
QMetaObject::invokeMethod(&a, "quit", Qt::QueuedConnection);
return a.exec();
}
You should set the progressBar value to 0 before showing it.
mProcessBarDlg->ui.progressBar->setValue(0);
mProcessBarDlg->show();
Related
Im trying to create an tic tac toe game, where buttons are used for the positions of where the knaughts and crosses are to be used. When I move the buttons into their respective places, the slot is not triggered and nothing happens.
`
#include "tic_tac_toe.h"
#include <iostream>
tic_tac_toe::tic_tac_toe(QWidget *parent)
: QMainWindow(parent)
{
setFixedSize(900,900);
initBoard();
//showBoard();
connect(button,SIGNAL(clicked()),this,SLOT(buttonpressed()));
}
tic_tac_toe::~tic_tac_toe()
{
}
void tic_tac_toe::initBoard()
{
int x = 0;
int y = 0;
for(int i = 0; i < 10; i++)
{
button = new QPushButton(this);
board.append(button);
button->show();
button->setFixedSize(300,300);
//button->setStyleSheet("border: 5px solid black");
button->setText("??");
// button->move(x,y);
// x = x + 300;
// if(x == 900)
// {
// y = y + 300;
// x = 0;
// }
}
}
void tic_tac_toe::showBoard()
{
}
void tic_tac_toe::buttonpressed()
{
button->setText("X");
}
I tried doing it with only one QPushbutton and it works, however when I move and create more buttons, the Slot function does not work on the buttons.
You only ever connect to the last QPushButton instance created. Move the connect call from the constructor into tic_tac_toe::initBoard and use a lambda to capture the value of button...
void tic_tac_toe::initBoard()
{
for (int i = 0; i < 10; i++) {
button = new QPushButton(this);
board.append(button);
button->show();
button->setFixedSize(300,300);
button->setText("??");
connect(button, &QPushButton::clicked, this,
[this, button]
{
buttonpressed(button);
});
}
}
Likewise, update the signature of tic_tac_toe::buttonpressed...
void tic_tac_toe::buttonpressed (QPushButton *button)
{
button->setText("X");
}
I simulated a dynamical device like mass spring damper.the QT Solves the equation of motion in Real Time and displays the output. I want to use an Qapplication object,to display Data and the outputs in "Real time". whole problem and display output is inside a loop.Everything is going well, but when the program reaches to command return a.exec() for display output,the GUI window Has come up and remain in the firest iteration." I expect don't gets stuck there and At each loop the program runs And at the end of loop update the GUI window in "Real time".
here is my code:
#include "QtWidgets/QApplication"
#include "QtWidgets/QGraphicsScene"
#include "QObject"
#include "QTimer"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Motion* ball = new Motion();
// create a scene
QGraphicsScene * scene = new QGraphicsScene();
QGraphicsRectItem* rect = new QGraphicsRectItem();
//show the view
view->show();
The Loop I talked about that.
for (int i = 0; i<int(j); i++)
{
Sleeper::msleep(50);
double t = time->getTime() + i*0.05;
states2 = world.openLoopSys;
for (int i=0; i<12; i++)
{
states1(i) = states2(i);
}
ball->run();
return a.exec(); // gets stuck there !!!
}
The Motion class is:
#include "motion.h"
Motion::Motion()
{
// create an item to put into the scene
setRect(0,0,20,30);
setPos(x(),y());
pos_x = 0;
pos_y = 0;
}
void Motion::run()
{
// connect
QTimer * timer = new QTimer();
connect(this,SIGNAL(timeout()),this,SLOT(move()));
timer->start(50);
}
void Motion::move()
{
setPos(x(),y()-5);
// setPos(0.01*pos_x,-0.01*pos_y);
}
How can I solve this problem?
I'm using QMovie and gif to create explosion after collision. The problem is that my gif is looping over and over, I've checked loopcount status and it returns -1 (infinite). How to display my gif just one time?
#include "Bullet.h"
#include <QTimer>
#include <QGraphicsScene>
#include <QList>
#include "Enemy.h"
#include "Game.h"
#include <typeinfo>
#include "levels.h"
extern Game * game; // there is an external global object called game
int Bullet::killed = 0;
int Bullet::missed = 0;
double Bullet::accurancy = 0;
Bullet::Bullet(QGraphicsItem *parent): QGraphicsPixmapItem(parent){
// draw graphics
setPixmap(QPixmap(":/images/res/images/bullets/bullet.png"));
missed++; // increse missed when bullet is created
movie = new QMovie(":/images/res/images/effects/explosion/64x48.gif");
processLabel = new QLabel;
processLabel->setMovie(movie);
// make/connect a timer to move() the bullet every so often
QTimer * timer = new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(move()));
// start the timer
timer->start(2);
}
void Bullet::move(){
// get a list of all the items currently colliding with this bullet
QList<QGraphicsItem *> colliding_items = collidingItems();
// if one of the colliding items is an Enemy, destroy both the bullet and the enemy
for (int i = 0, n = colliding_items.size(); i < n; ++i){
if (typeid(*(colliding_items[i])) == typeid(Enemy)){
// increase the score
game->score->increase();
//play explosion animation
movie->start();
movie->setSpeed(180);
processLabel->setAttribute(Qt::WA_NoSystemBackground);
processLabel->setGeometry(QRect(x()-15,y()-15,64,48));
scene()->addWidget(processLabel);
qDebug() << movie->loopCount();
//connect(movie,SIGNAL(finished()),movie,SLOT(stop()));
// remove them from the scene (still on the heap)
scene()->removeItem(colliding_items[i]);
scene()->removeItem(this);
// delete them from the heap to save memory
delete colliding_items[i];
delete this;
killed++;
missed--; // decrese missed if bullet colide with enemy
if((killed+1) % 9 == 0)
{
game->level->Levels::incrementLevels();
game->score->Score::addToSum(); /// TODO
}
//qDebug() << "Already killed: " << killed;
//qDebug() << "Already missed: " << missed;
// return (all code below refers to a non existint bullet)
return;
}
}
// if there was no collision with an Enemy, move the bullet forward
setPos(x(),y()-1);
// if the bullet is off the screen, destroy it
if (pos().y() < 0){
scene()->removeItem(this);
delete this;
}
}
I had the same question and didn't find anything, so here's my solution:
connect the signal "frameChanged(int)" to:
void Bullet::frameChanged_Handler(int frameNumber) {
if(frameNumber == (movie->frameCount()-1)) {
movie->stop();
}
}
If you want to run X times the loop you just have to add a static counter to know how many times you've passed the last frame:
void Bullet::frameChanged_Handler(int frameNumber) {
static int loopCount = 0;
if(frameNumber == (movie->frameCount()-1)) {
loopCount++;
if(loopCount >= MAX_LOOP_TIMES)
movie->stop();
}
}
and of course, connect with this:
connect(movie, SIGNAL(frameChanged(int)), this, SLOT(frameChanged_Handler(int)));
That's it... Hope it can help you.
I'm working on UI using QT. The ui is simple, it's app based like IPhone or Android. Say there are 9 items (3 rows x 3 cols).
What I want to do is to navigate between widgets using arrow keys.
If the focus is in [row 1,col 1] and I press down arrow, I want it to go to [row 2, col 1]
another example.
If the focus is in [row 2,col 3] and I press up arrow, I want it to go to [row 1, col 3]
But the current behavior is up and right always go to next widget and down and left always go to previous widget.
Is there any way to do this in qt? or I need to create some algorithm to do this?
Thanks
UPDATE: See amazing example at the end.
Basic Widget focus navigation starts out with this:
http://qt-project.org/doc/qt-4.8/focus.html
Arrow navigation is available easily with a QTableView:
http://qt-project.org/doc/qt-4.8/qtableview.html#navigation
If you can get your widgets to work inside the structure of a QTableView, then you don't need to implement it, it comes as a part of the wrapper/view widget.
http://qt-project.org/doc/qt-4.8/qtablewidget.html#details
http://qt-project.org/doc/qt-4.8/model-view-programming.html
Model View programming does have a learning curve, but it is worth while to learn and use.
But this is by no means the only way to accomplish this.
There are event filters, key events, focus events that can be leveraged to accomplish this feat without using a QTableView or QTableWidget. But figuring out the best way to do it without making it look messy may take some time.
http://qt-project.org/doc/qt-4.8/qcoreapplication.html#notify
http://doc.qt.digia.com/qq/qq11-events.html
http://qt-project.org/doc/qt-4.8/eventsandfilters.html
http://qt-project.org/doc/qt-4.8/qkeyevent.html#details
http://qt-project.org/doc/qt-4.8/qfocusevent.html
Key events are set to the item with the focus, and if they ignore the event it propagates up to its parent. So as long as your items in your table/grid ignore the key events having to do with the arrow keys, then you could have your parent widget listen for the key events and handle them appropriately.
http://qt-project.org/doc/qt-4.8/qt.html#Key-enum
http://qt-project.org/doc/qt-4.8/qt.html#FocusReason-enum
http://qt-project.org/doc/qt-4.8/qwidget.html#setFocus
http://qt-project.org/doc/qt-4.8/qapplication.html#focusWidget
Hope that helps.
EDIT: Fully working example in QGraphicsView of what you want to do:
Qt Creator > Welcome tab > Examples > Pad Navigator Example
http://qt-project.org/doc/qt-4.8/graphicsview-padnavigator.html
Here is the relevant code from the example:
// Enable key navigation using state transitions
for (int y = 0; y < rows; ++y) {
for (int x = 0; x < columns; ++x) {
QState *state = stateGrid[y][x];
QKeyEventTransition *rightTransition = new QKeyEventTransition(this, QEvent::KeyPress,
Qt::Key_Right, state);
QKeyEventTransition *leftTransition = new QKeyEventTransition(this, QEvent::KeyPress,
Qt::Key_Left, state);
QKeyEventTransition *downTransition = new QKeyEventTransition(this, QEvent::KeyPress,
Qt::Key_Down, state);
QKeyEventTransition *upTransition = new QKeyEventTransition(this, QEvent::KeyPress,
Qt::Key_Up, state);
rightTransition->setTargetState(stateGrid[y][(x + 1) % columns]);
leftTransition->setTargetState(stateGrid[y][((x - 1) + columns) % columns]);
downTransition->setTargetState(stateGrid[(y + 1) % rows][x]);
upTransition->setTargetState(stateGrid[((y - 1) + rows) % rows][x]);
EDIT:
Amazing example using QShortcuts and a QGridLayout and a bunch of QPushButtons:
widget.cpp
#include "widget.h"
#include <QPushButton>
#include <QApplication>
#include <QShortcut>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
m_grid = new QGridLayout;
for(int r = 0; r < 10; r++)
{
for(int c = 0; c < 10; c++)
{
m_grid->addWidget(new QPushButton("Row " + QString::number(r)
+ ", Col " + QString::number(c)),
r, c);
}
}
this->setLayout(m_grid);
m_grid->itemAtPosition(1, 1)->widget()->setFocus();
this->setStyleSheet("QPushButton::focus{ background: black; color: white;}");
// only works for in Qt for Embedded Linux, Symbian and Windows CE only.
// QApplication::setNavigationMode(Qt::NavigationModeKeypadDirectional);
QShortcut * shortcut;
shortcut = new QShortcut(QKeySequence(Qt::Key_Up),this,
SLOT(on_up()));
shortcut = new QShortcut(QKeySequence(Qt::Key_Down),this,
SLOT(on_down()));
shortcut = new QShortcut(QKeySequence(Qt::Key_Left),this,
SLOT(on_left()));
shortcut = new QShortcut(QKeySequence(Qt::Key_Right),this,
SLOT(on_right()));
}
void Widget::on_up()
{
moveFocus(0, -1);
}
void Widget::on_down()
{
moveFocus(0, 1);
}
void Widget::on_left()
{
moveFocus(-1, 0);
}
void Widget::on_right()
{
moveFocus(1, 0);
}
void Widget::moveFocus(int dx, int dy)
{
if(qApp->focusWidget() == 0)
return;
int idx = m_grid->indexOf(qApp->focusWidget());
if(idx == -1)
return;
int r, c, rowSpan, colSpan;
m_grid->getItemPosition(idx, &r, &c, &rowSpan, &colSpan);
QLayoutItem* layoutItem = m_grid->itemAtPosition(r + dy, c + dx);
if(layoutItem == 0)
return;
layoutItem->widget()->setFocus();
}
Widget::~Widget()
{
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QGridLayout>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
QGridLayout * m_grid;
public slots:
void on_up();
void on_down();
void on_left();
void on_right();
void moveFocus(int dx, int dy);
};
#endif // WIDGET_H
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
To enable keypad navigation, build Qt with QT_KEYPAD_NAVIGATION defined.
https://het.as.utexas.edu/HET/Software/html/qapplication.html#keypadNavigationEnabled
I have a class ClientWindow. I have created several instances of it and appended the their pointers to a a list. If i try to show any of the windows however, I get "Segmentation fault (core dumped)" I keep the list of windows in a class called controller.
Here is my controller header file:
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include "clientwindow.h"
class Controller
{
public:
Controller();
void createClients(int num);
void showWindows();
private:
QList<ClientWindow*> clWList;
int size;
};
#endif // CONTROLLER_H
this is the cpp file:
#include "controller.h"
Controller::Controller()
{
}
void Controller::createClients(int num)
{
size = num;
for(int i = 0; i < size; i++)
{
ClientWindow cw;
clWList.append(&cw);
}
}
void Controller::showWindows()
{
for(int i = 0; i < size; i++)
{
ClientWindow* cw = clWList.at(0);
cw->show();
}
}
this is my main:
#include <QtGui/QApplication>
#include "clientwindow.h"
#include "controller.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// ClientWindow w;
// w.show();
QString temp = argv[1];
bool ok;
int tempI = temp.toInt(&ok, 10);
Controller c;
c.createClients(tempI);
c.showWindows();
return a.exec();
}
This is where it goes wrong:
for(int i = 0; i < size; i++)
{
ClientWindow cw;
clWList.append(&cw);
}
A local variable cw is created on the stack in each iteration. It is deallocated at the end of each iteration. Meaning the data is gone. So you end up storing pointers pointing to junk.
Calling a member function of a junk typically results in crash. :) Do this instead:
for(int i = 0; i < size; i++)
{
ClientWindow * cw = new ClientWindow();
clWList.append(cw);
}
You'll have to go through the list and delete the objects after you are done with them.