I am new to Qt and I am using QMediaPlayer in one of my GUI projects and I want to stop the loaded video at a certain position X (input from user on a Line Edit) how would I be able to do this? I know I am able to set a starting position just by doing player->setPosition(Y) where Y is an integer but what about an ending position?
One lesser option would be to use position() which returns the current position as a qint64 - if you call the play() method for your QMediaPlayer then use something like
while (player.position() < input) {}
player.stop(); // Or player.pause();
it will wait until the input position is reached. But the drawback to that approach is the blocking while loop and without knowing the intended application I don't know if that would be appropriate. It is probably better to use the QMediaPlayer::positionChanged signal (which is emitted based on the QMediaPlayer's notifyInterval), something like
connect(player, SIGNAL(positionChanged(qint64)), this, SLOT(checkPosition());
where it is assumed this is the receiver and both player and input are scoped such that they are available to the slot checkPosition(). checkPosition() then looks something like
checkPosition() {
if (player.position() > input()) {
player.stop(); // Or player.pause();
}
}
Of course you can also pass the player and the input to the checkPosition() slot but I neglected that for simplicity. Hope this helps.
Related
I wrote in C++ a solver for the 8-puzzle game, and now I'm trying to use Qt to give it a GUI.
Basically I have an underlying object of type "Board" which represents the board of the puzzle, and I have organized the GUI as a grid of QPushButton. Then I have a method updateUI which associates to every button the correct text, based on the Board. Something like
for(int i=0; i<Board::MATRIX_DIM * Board::MATRIX_DIM; i++)
{
m_buttons[i]->setText(m_values[i]);
}
In another method (solveGUI) I have
void MainWindow::solveGUI()
{
m_game->solve();
int solutionDepth = m_game->getSolutionDepth();
Move *solutionMoves = m_game->getSolutionMoves();
for(int i=0; i<solutionDepth; i++)
{
Move m = solutionMoves[i];
m_board.performMove(m); /* perform the move on the Board object */
updateUI(); /* should update the GUI so that it represents the Board */
Sleep(1000);
}
}
where the first line (m_game->solve) takes some time. Then I obtain a list of the moves performed, in solutionMoves, and what I would like to do is showing this moves on the board, with some delay between a move and the next one. This method is called by my main, which looks like this:
QApplication app(argc, argv);
MainWindow w;
w.show();
w.solveGUI();
return app.exec();
The result is that the GUI hangs and, after some time, it displays only the solution, completely skipping the moves.
What am I missing? Thank you!
P.S. I don't think I need a different Thread for the solver because I want the solver to run before the solution is displayed. Is it right?
It's app.exec() that actually runs the main loop which handles all events, including displaying GUI. If you want to call solve() before that, it's OK, but if you want to actually display and update GUI before exec(), it's wrong. I'm not sure if it's totally impossible, but it's definitely not the right way to do it.
There are two ways around it. The more canonical way is to redesign a program using a QTimer. Then everything will be smooth and responsive. But that can be tedious sometimes. In your case it should be quite easy, though. Just save the results somewhere, and call a slot using a QTimer object every 1000 seconds - it will have the same effect as your Sleep(), but will keep everything responsive.
The other solution is to call your solveGUI() method after exec() starts its job. It can be done, for example, using QTimer::singleShot():
QTimer::singleShot(0, &w, SLOT(showGUI()));
return app.exec();
Then, before each Sleep(), you should call QApplication::processEvents(), which basically allows you to temporary yield control, processing all pending events, including GUI updates. This approach is somewhat easier, but it's inferior since the GUI still freezes at each Sleep(). For example, if the user wants to exit the application, or if the window is needed to be repainted, it will cause uncomfortable GUI lags.
You're stalling the main thread (which also does the event processing) and rendering it uncapable of responding to keyboard/mouse/window messages.
You should use an asynchronous timer operation instead of the sleep function: use a QTimer to delay showing the next solution and avoid messages being left unanswered for too long.
There is a nice article of methods to keep the GUI responsive during processing loops. if it's not a complicated case I think, just insert QCoreApplication::processEvents(); inside the long processing loops.
try the following:
void MainWindow::Wait(int interval ) {
QTime timer = new QTime;
timer.restart();
while(timer.elapsed() < interval) {
QApplication::processEvents();
}
}
...
for(...) {
//wait 1 second (1000 milliseconds) between each loop run at first
Wait(1000);
...
}
...
not tested yet - but should work (maybe there is some cpu load)!
I'm developing a game with QtQuick 2 (Qt5.2) QML and C++. I want most of the game-logic in C++ (I don't want to do it with JS), and I'm trying to use QStateMachines for a lot of the logic.
Now my question is, how do I implement a proper game-loop in that scenario?
The game has for example objects that are moving from and to certain waypoints on the screen, so I think I can't do everything state/event-based. At some point I need to say "my object should move 10 pixels in direction x every second". So for example when my object is in its state "moving", it should move by a certain amount every second and then of course check for some conditions if it has to switch the state (e.g. to "attacking").
Now all the demos in the Qt-examples and on the web seem to be either fully event-based (e.g. four-in-a-row-wins-like) or written in JavaScript. So I am a bit lost here.
One idea I could find was to create a QTimer with a timer of e.g. 30ms and connect that QTimer's timeout() signal to an advance() slot of every moving object, and start that timer before 'return app.exec();'. Like this:
QTimer timer;
QObject::connect(&timer, SIGNAL(timeout()), &scene, SLOT(advance()));
timer.start(1000 / 33);
return app.exec();
and then each object (e.g. the Mouse) has a
void Mouse::advance(int step)
However, this requires a QGraphicsScene and I'm not sure how well that goes with a QtQuick/QML project on Android/iOS.
Is that a good solution? Or is my view of the problem somehow wrong and I don't need a game loop to accomplish my goal?
The solution shouldn't use any desktop-only stuff from Qt, i.e. it should work on Android, iOS and desktops.
That's the way to go: QTimer. Here you find some detailed example on it:
A typical loop for game in Qt:
int main(int argc, char* argv[]) {
// init stuff
while(game.isRunning()) {
a.processEvents(); //(a is a QApplication created during the init, should use a better name i guess)
QTime currentTime= QTime::currentTime();
int timeSinceLastUpdate = lastUpdate.msecsTo(currentTime);
while(timeSinceLastUpdate>updateTimeStep){
game.update();
timeSinceLastUpdate-=updateTimeStep;
lastUpdate=lastUpdateaddMSecs(updateTimeStep);
}
renderer.setInterpolateFraction(static_cast<float>(timeSinceLastUpdate)/static_cast<float>updateTimeStep);
renderer.renderGameObjects();
renderer.renderGUI();
renderer.swap();
}
a.exit();
return 0;
}
Source: Game loop in Qt
Making a Simple Game Loop with QTimer
Qt as a game engine
That's should be enough info for you to get started.
Usual game loop of simple game can look like this (not sure if I understand you correctly though).
Each class that represents game object have 2 public methods: update(); and render();
On each call of QTimer object you iterate over all game objects and call their update method. After it you repeat the same for render method();
In update methods each object decides what to do on game map (move/shot/stand/...) and changes its coordinates/properties. In render methods each object just draws itself on display.
I'm making a console game called alien spaceships as a homework. It should look something like this http://img74.imageshack.us/img74/8362/alieninvadersfdcl192720mu1.jpg .
So far so good I ain't allowed to use classes nor objects => only functions and arrays.
I have one while loop that checks the buttons I press on the keyboard and according to the button applies some functions.
The problem comes when I try to shoot a missle because it's done with a "for" loop and when I shoot I can't move. Can someone give me an idea how the model is supposed to look like and how can I make something like this work. I don't think it's needed to post my code, but if you want I'll post it.
I assume that you're not willing to play with multiple threads. It is not mandatory for a simple game like this and would add a bit of complexity.
So generic loop for monothreaded game is:
state new_state = createInitialState();
do
{
input = readInput(); // non blocking !
new_state = modifyState(input, new_state);
updateScreen(new_state);
}
while (!exitCondition(input));
None of these functions should loop for long.
In your case, the missile position should be updated in modifyState taking into account the time since the last modifyState.
I assume you use a matrix to store all the data, and periodically you print the content of the matrix (that's how you create a console game).
So, your code should look something like this:
render()
{
update_position(x,y);
if(missile_fired)
update_missile_position();
}
main()
{
for(;;)
{
read_input(&x,&y);
render();
draw_image();
}
}
I have a custom widget which displays many items in rows:
void update(){ //this is a SLOT which is connected to a button click
QVBoxLayout *layout = this->layout();
if (layout == NULL){
layout = new QVBoxLayout;
this->setLayout(layout);
} else {
QLayout_clear(layout); //this is a function that I wrote that deletes all of the items from a layout
}
ArrayList *results = generateData(); //this generates the data that I load from
for (int i = 0; i < results->count; i++){
layout->addWidget(new subWidget(results->array[i]));
}
}
The problem is that there are about 900 items and a profile reveals that simply adding the child object to the layout takes 50% of the time (constructing takes the other 50%). Overall it takes about 3 seconds to load all of the items.
When I click on the button to load more data, the entire UI freezes for the 3 seconds and then all of the items appear together when everything is done. Is there a way to progressively load more items as they are being created?
The first trick is, as Pavel Zdenek said, to process only some of the results. You want to process as many together so that the overhead (of what we're going to do in the next step) is low, but you don't want to do anything that would make the system seem unresponsive. Based on extensive research, Jakob Nielsen says that "0.1 seconds is about the limit for having the user feel that the system is reacting instantaneously", so as a rough estimate you should cut your work into roughly 0.05 second chunks (leaving another 0.05 seconds for the system to actually react to the user's interactions).
The second trick is to use a QTimer with a timeout of 0. As the QTimer documentation says:
As a special case, a QTimer with a timeout of 0 will time out as soon
as all the events in the window system's event queue have been
processed. This can be used to do heavy work while providing a snappy
user interface.
So that means that a timer with a timeout of 0 will be executed next, unless there is something else in the event queue (for instance, a mouse click). Here's the code:
void update() {
i = 0; // warning, this is causes a bug, see below
updateChunk();
}
void updateChunk() {
const int CHUNK_THRESHOLD = /* the number of things you can do before the user notices that you're doing something */;
for (; i < results->count() && i < CHUNK_THRESHOLD; i++) {
// add widget
}
// If there's more work to do, put it in the event queue.
if (i < results->count()) {
// This isn't true recursion, because this method will return before
// it is called again.
QTimer::singleShot(0, this, SLOT(updateChunk()));
}
}
Finally, test this a little bit because there's a gotcha: now the user can interact with the system in the "middle" of your loop. For instance, the user can click the update button while you're still processing results (which in the above example means that you would reset the index to 0 and reprocess the first elements of the array). So a more robust solution would be to use a list instead of an array and pop each element off the front of the list as you process it. Then whatever adds results would just append to the list.
#Adri is generally right, the twist is that the "another thread" must be the UI thread again. The point is to allow UI thread's event loop to keep spinning. The fast and dirty way is to put QCoreApplication::processEvents() in your for() cycle. Dirty because, as the doc says, it should be called "ocassionally". It might have some overhead even if there are no UI events, and you are messing Qt's performance optimization as to when and how often spin the loop. Slightly less dirty would be to call it only ocassionally, after chunks of result.
Cleaner and proper way is to create a private slot, which pops one result element (or chunk, to speed up), adds to the layout and increments index. Then it will recall itself until end of results. The gotcha is to define connect() with forced connection type Qt::QueuedConnection, so it will get deferred after already queued UI events (if any).
And because you run in only one thread, you don't need any locking over results.
Adding example per OP's request:
While #TomPanning solution is correct, it kind of hides the real solution behind QTimer which you don't need - you don't need any timing, you just need a specific non-timer behavior upon specific parameter value. This solution does the same thing, minus the QTimer layer. On the other hand, #TomPanning has a very good point about the plain ArrayList not being very good data storage, when interaction can happen in between.
something.h
signals: void subWidgetAdded();
private slots: void addNextWidget();
ArrayList* m_results;
int m_indexPriv;
something.cpp
connect(this,SIGNAL(subWidgetAdded()),
this,SLOT(addNextWidget(),
Qt::QueuedConnection);
void addWidget() {
// additional chunking logic here as you need
layout->addWidget(new subWidget(results->array[m_indexPriv++]));
if( m_indexPriv < results->count() ) {
emit subWidgetAdded(); // NOT a recursion :-)
}
}
void update() {
// ...
m_results = generateData();
m_indexPriv = 0;
addNextWidget(); // slots are normal instance methods, call for the first time
}
I need to block signals that I emit (indirectly) myself.
In C one could use g_signal_handlers_block_by_func() and the sister function unblock.
What can I use in C++ gtkmm?
I have a gtkmm dlna player, that emits the changed signal to a Gtk::HScale Widet each second, because it gets (from the outside) a signal that the song that just plays. And then I seek to the position that just where current, which set the song back a split second...
I would like to block my on changes from the seek, because I saw that a C program did that with g_signal_handlers_block_by_func.
since ptomato asked:
I never realized, that the connect method has a valuable return value:
so if you connect the signals like this:
mywidget_connection = mywidget.signal_value_changed().connect(sigc::mem_fun(*this, &MyClass::on_value_changed ));
In my situation I have 2 ways to change the value:
1.) someone pulls a slider: should update the value and seek
2.) the timer comes along and tells the new position: should update the value but not seek.
then you can block/unblock like this:
mywidget_connection.block();
mywidget.set_value(new_value);
mywidget_connection.unblock();
and this does not emit the changed signal.