Qt C++: How to make a for loop until a button is pressed - c++

I have been trying to make a GUI Blackjack game in C++ with Qt. However, I have hit a road block on my way. I made the game and the game logic last year in pure C++ (link below). I am trying to use the same code to build the GUI version of the game Github/Blackjack.
It's mostly done to the point that I have the cards showing up, adding the values of those cards, the dealer and the player set up.
In the C++ version I made a vector of all the players and added the dealer to the end of it, then using a for loop, I would iterate through the players to get them to play.
In Qt, I have created a widget with two buttons "Hit" and "Stand" for the player control.
"Hit" button is simple and connected the click event of the button with the hit member function of the player.
ctrl = new PlayerControl(nullptr, mainPlayer);
connect(ctrl->ui->hitButton, &QPushButton::clicked, [mainPlayer]{
mainPlayer->hit();
});
Code for iterating through the vector:
for (size_t i = 0; i < players.size(); i++)
{
if (i == playerPos - 1)
{
ctrl->setVisible(true);
//how to make the loop to pause here until the user presses the
//"Stand button", and then proceed with the rest of the loop?
}
else if (i == players.size() - 1)
dealerPlay();
else
computerPlay(players[i]);
}
I'll really appreciate any help. :)

I don't really understand the code you are showing or how it relates to the question in the title of your post. I'll just answer the question, which is:
How to make a for loop until a button is pressed
The answer is that you probably don't want to do that, because that would involve multi-threading or some kind of complicated concurrency mechanism. When you're writing a GUI, the main thread of your application usually sits in a loop waiting for event messages (like clicks and key presses) from the operating system. When it gets such a message, it is supposed to handle them quickly and then go back to waiting for the next message.
In Qt, you can handle these events by overriding functions in your QMainWindow class or by connecting Qt signals to slots.
So, instead of having a loop that iterates through each player and waits for them to make their move, you would have some long-living variables that keep track of the state of the game, and when you detect that a player has made a move (i.e. by clicking a button), you would update those variables, update any data shown on the screen, and then return from your event handler so you can handle the next event.

Related

Simulation loop with Qt

I have to create a cookie factory simulation program for an assignment. The program's GUI uses normal Qt widgets (such as: labels, buttons, and line edits) to control the simulation variables and objects. I already created the GUI, but I don't know how to do the simulation.
Our teacher suggested using threads (one per machine). I read on QThreads, but got the impression (from this link) that they are not really ideal for accessing objects from other threads, and I don't really know how to create or handle them.
However, the simulation is simple enough that (I believe) it could be done with only one loop (one thread), but I don't know how to create this loop in the QMainWindow class.
So, my main question is: How can I run a loop that can access the GUI, can be accessed by the GUI (so that it can change machines' values), and can access the machines? I just don't really know how to connect the GUI and the simulation.
Thanks, sorry for the long post.
Edit #1: Pseudo-code of what I am trying to do:
// Machines' initialization:
rawMaterialsTransport = new RawTransport();
doughMachine->conveyour = doughConveyour;
// Simulation loop:
lastTime = 0
while(running) {
// Handle pauses.
while(simulationPaused) {
sleep(100);
}
// Update machines/do the simulation
timePassed = now() - lastTime
lastTime = now()
rawMaterialsTransport->update(timePassed);
doughMachine->update(timePassed);
chocolateMachine->update(timePassed);
doughConveyour->update(timePassed);
// Update the GUI
chocolateGramsProcessedLabel->setText(to_string(chocolateMachine->gramsProcessed()));
// Sleep so as to not waste
sleep(100);
}
// On the GUI side:
onLineEditEnter() {
doughMachine->gramsPerSecond = double(lineEdit->text);
}
onPauseButtonPress() {
simulationPaused = !simulationPaused;
}
You could use signals and slots.
In the GUI, you connect the signals emitted by your GUI items (the buttons, line edits, etc.) to a custom slot which does the business logic. For example buttons emit the clicked signal when pressed.
If the processing of the business logic in the slot has terminated, you emit another signal that is connected to a slot in your widget which updates the GUI.
If the GUI hangs, i.e. the processing of the business logic takes too much time, you have to start another thread for doing the business logic.
Signals and slots also work across threads.
References
The signals and slots documentation.
The documentation of the connect methods.
The list of signals a QAbstractButton emits.
Signals and slots across threads. This page also contains references to examples.
Blocking Fortune Client Example where a thread runs in a loop.

How to create a control flow? C++

First of all, sorry for the generic title, I didn't know who to write my question.
I'm in a trouble, i'm trying to create a control but I don't know how to do it. Here is what I would like to do:
I created a chronometer (just an int that increase 1 by 1) and I want to write that: If clickNumber == 1 and the chronometer is less than 144, wait until it reach this number, if it is 144, then make and action, then exactly the same, if clickNumber == 2 and the chronometer is less than 72, wait until it reach this number, if the chronometer is == 72 then make and action.
I think it might be so easy to do, but I can't see how to do it.
Thank you all
Your issue is better thought in terms of events and objects.
Let's say you have a Chronometer and it has at least three parts: Display, button and code. The display will show the value of the chronometer. The button will behave as you describe. The code is the part that manages everything.
Your chronometer code will be receiving events from at least two sources: Timer and Button. The timer is a system time that sends you message periodically (like once a second). The button will send your chronometer code an event when the user clicks on the button.
So you will need to have some static variables to hold your information.
You will need to think in terms of the event:
if event == button click
then increment click and check click count.
endif
if event == timer
then
increment chronometer value.
if chronometer value == limit, then stop the timer.
endif
The implementation of the algorithm depends on the GUI framework you are using.

C++ Qt Inherit QMessageBox to delay user input in order to prevent unintended action

Problem
Windows has a system setting that will cause the mouse pointer to jump (move) to a new focus element automatically, e.g. the default button of a dialog that pops up. While the advantage is an increase in speed and a reduction of mouse movements, it has a disadvantage:
If this happens just when before the user clicks on another element, the user is unable to abort his/her action in time and will immediately accept the dialogs default button because the focus is moved by the system. Usually this may entail cumbersome work to retrace the steps up to this point (think a file chooser dialog that forgot the very long path you input previously) but it could also mean triggering an irreversible process (e.g. file deletion).
Aim
Essentially I would like to disable the dialog's inputs for a small amount of time, just enough to prevent an inadvertant mouse click or keyboard button press.
Question
It comes down to a C++ question, namely how to access the base classes' objects (GUI widgets) from the inheriting class, i.e.
disable the button widgets of a QMessageBox
start a single shot QTimer and connect it to a slot that
enables the previously disabled widgets
(As alternative, I probably could reimplement input event handlers that suppress all input for a specific amount of time, but although I intend to keep that time very short (e.g. 100 ms), the user is not informed of the disabled input using that method.)
A simple class derived from QDialogBox can be found at http://www.qtforum.org/article/24342/messagebox-auto-close-mouse-event-close.html.
Do you need to use one of the "native"-ish message boxes provided by the QMessageBox static functions?
Otherwise, that's pretty simple to achieve, by building a QMessageBox and adding standard buttons to it:
QMessageBox *messageBox = new QMessageBox;
QPushButton *okButton = messageBox->addButton(QMessageBox::Ok);
okButton->setEnabled(false);
// use a QTimer to add logic to reenable the button
// use QCursor to move the mouse cursor on the button
// add a nice countdown in the button's label, like Firefox does
// add other nice UX touches as wanted
Last points are left as an exercise to the reader :)
To en/disable the buttons in QMessagebox one would need access to them.
qmessagebox.cpp uses buttonBox = new QDialogButtonBox; and the addButton() method
d->buttonBox->addButton(button, (QDialogButtonBox::ButtonRole)role);
d->customButtonList.append(button);
But I don't understand Qt internals and am unable to find these in qmessagebox.h and thus fail to find out if there is a chance to access the buttons..

Qt Scrolling problems

I have implemented a widget which has a grid (QTableView object) and two scollbars, one horizontal and one vertical. I have implemented a function that fetches the data to be shown in the grid from a database. I want when the user pressed the arrow from the scroll bar in order to make a single step the application instntly fetch the data. On the contrary when the user scrolls with the whell or move the slider the app don’t fetch the data instantly. More specifically i want the data to be fetched when the user stops the slider for some time or releases the slider. For this reason i have used sliderReleased() signal. Moreover, i have write, as a user from this forum suggested, this code for the vertical scrolling actions.
void handleVTableScrollAction(int action)
{
switch(action)
{
case QAbstractSlider::SliderSingleStepAdd:
case QAbstractSlider::SliderSingleStepSub:
drawGrid();
requestSlot();
break;
case QAbstractSlider::SliderMove:
drawGrid();
m_Timer.start(500);
}
the timer is connected to a slot the fetches the data
connect (&m_Timer, SIGNAL(timeout()), this, SLOT (requestSlot()));
So my problem is when i wnt to make a single step (by pressing the arrow key) the app don’t responds instantly. When i press the arrow for the firtst time nothing seems to be done, but when i am pressing second time the grid follows the movement. All the other movements(wheel and slider move) work fine.
So i tried to use the valueChange() signal just like this:
connect(ui->verticalScrollBar, SIGNAL(valueChanged(int)), this, SLOT(sliderSigleStep()));
connect(ui->verticalScrollBar, SIGNAL(sliderMoved(int)), this, SLOT(sliderMoveSlot()));
In this way the single step works fine, but the sliderMoveSlost is never called as the valueChanged singal is always emmited first.
Is there an explantion for my first issue?
Can i call a function with the condition that two signals emmited? For example call the sliderMoveSlot only if sliderMove(int) and valueChanged(int) singals emmited and call sliderSingleStep() if only valueChanged(int) is emmited.

How can I hold my running function until I click the button in c++ form?

I am using .net framework 4 and visual studio 2010.
I am working with c++ form.
My code is something like that:
int k = 0;
void writeFunction(int &k){
++k;
textbox1->text = Convert::toString(k);
//i want to suspend writeFunction in there, until i click the button1 which is on Form1
//because i don't want to stop function, it has to wait to click
//after i clicked the button1 , the program continue to run code here
writeFunciton(k);
}
Can you add more details about your program? What framework are you using to generate the form, and how do button presses interact with your code?
For example, if you're using Qt then you could use signals and slots to link pressing the button with your method. Depending on the framework there might be other appropriate answers.
Generally I would recommend using a threading library to synchronize your code.
It is not wise to suspend a GUI function..instead of that use operation state variable in your form class such as
enum OperationState
{
os_normal,
os_pointselection,
os_event1,...
}
After you call textbox->=...
swicth to selection state and by using this state track mouse states like click after mouseclick check for os_selection state,then continue you duty..