Qt - using windows Sleep() - sleep

I want to put a brief delay in my Qt program but it's behaving oddly. This is my code...
void ScribbleArea::keyPressEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_Right)
{
myLabel->setText("You pressed RightArrow");
Sleep(1000);
myLabel->setText("Done waiting");
}
}
What I expect to happen is to see "You pressed RightArrow" followed by a 1 second pause and then "Done waiting". But it behaves as if the Sleep() is called prior to the first setText().
Any thoughts would be greatly appreciated.

Related

FLTK window not showing in while loop c++

I am trying to implement a game loop in FLTK
void SnakeFLTK::init() {
_display = new Fl_Window(900, 600);
if (!_display)
throw SnakeFLTKException("Couldn't make fltk window!");
_display->color(FL_BLACK);
_display->show();
while (!_doExit) {
std::cout << "-->" << std::endl;
}
Fl::run();
}
the problem I have is the window is not showing. I want to keep showing and redrawing on the window in the while (!_doExit) loop and it's important that I use _doExit. I have tried using
while (Fl::wait > 0)
but this method seems to have its own loop that waits for events.
How do I Implement a loop like I did and show the window?
FLTK is doing nothing until Fl::run is called. And as this, you can not do anything after you call Fl::run because the function returns only if main window is closed.
Exactly for doing something while Fltk itself is "running" you can register to the idle loop like this:
void CallbackFunc( void* )
{
std::cout << "Hallo" << std::endl;
}
int main() {
auto _display = new Fl_Window(900, 600);
_display->color(FL_BLACK);
_display->show();
Fl::add_idle( CallbackFunc );
Fl::run();
}
In the given callback function you can do the drawing or anything youl like to achieve in FLTK which is not driven by events coming from the active widgets itself.

Understanding behaviour of QProcess signals with a lambda function

This was a problem in Qt 5.4.0. and has been fixed in Qt 5.6.0
I have an application that allows the user to launch a process with QProcess.
Initially I wanted to connect the QProcess::finished signal to a lambda function, but since it is an overloaded function, it appears that it can't be done due to ambiguity of which function to connect with.
Therefore, I've experimented with monitoring the state change of QProcess.
void MainWindow::on_actionLaunchApplication_triggered()
{
// launch the file open dialog for the user to select a file
QString filePath = QFileDialog::getOpenFileName(this, "Select Application to Launch", "/Applications");
if(filePath == "")
return;
QProcess* proc = new QProcess(this);
// can't connect to QProcess::exited with lambda, due to its overloaded function, so will check state changed instead
connect(proc, &QProcess::stateChanged, [filePath, proc, this](QProcess::ProcessState state){
if(state == QProcess::NotRunning)
{
qDebug << "Deleting proc";
disconnect(proc, &QProcess::stateChanged, 0 , 0);
proc->deleteLater();
}
});
proc->start(filePath);
}
Generally this works as expected; the application selected is executed and different applications can be selected to run this way, one after another. Quitting such an application results in execution of the tidyup code that deletes the QProcess.
However, if an application that has been launched with QProcess is quit and then selected again for execution, it fails to launch and instead the process is deleted immediately from the call to deleteLater in the lambda function.
So, what's going on? Considering that a new QProcess is created each time, why would it work the first time for each application, but if such an application is quit and selected to launch again, it is instantly deleted?
I'm fully aware that I can connect to QProcess::finished without a lambda function or via the SIGNAL and SLOT macros. This question is academic and I'm looking for an understanding of what's going on here.
In response to answers and comments so far, it looks like this is a Qt bug. Connecting to the QProcess::finished slot results in the same problem of an application only being launched the first time.
// launch the file open dialog for the user to select a file
QString filePath = QFileDialog::getOpenFileName(this, "Select Application to Launch", "/Applications");
if(filePath == "")
return;
QProcess* proc = new QProcess();
connect(proc, static_cast<void (QProcess::*)(int)>(&QProcess::finished), [filePath, proc, this](int exitStatus) {
Q_UNUSED(exitStatus);
Log("Deleting proc for launched app");
proc->deleteLater();
proc->disconnect(proc, static_cast<void (QProcess::*)(int)>(&QProcess::finished), 0, 0);
});
proc->start(filePath);
In fact, you can connect to the signal! All you have to do is to tell you compiler which signal it should choose, because it can't decide this.
There is a good answere to that problem in this question: Qt5 overloaded Signals and Slots.
This won't solve your problem with the strange delete behavior, but maybe the problem will solve itself this way.
The finished signal indicates a state transition. But instead, you're checking for a static state, not a transition.
You should keep a property related to the process to indicate that it is running or starting, and then only delete the process when it stops running or fails to start.
void MainWindow::on_actionLaunchApplication_triggered()
{
auto locations = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation);
if (locations.isEmpty())
locations << QString();
auto filePath = QFileDialog::getOpenFileName(this, "Select Application to Launch",
locations.first());
if (filePath.isEmpty())
return;
bool wasActive = false; // upon capture, it becomes a per-process field
auto proc = new QProcess(this);
connect(proc, &QProcess::stateChanged, [=](QProcess::ProcessState state) mutable {
if (state == QProcess::Running) {
qDebug() << "Process" << proc << "is running";
wasActive = true;
}
else if (state == QProcess::Starting) {
qDebug() << "Process" << proc << "is starting";
wasActive = true;
}
else if (state == QProcess::NotRunning && wasActive) {
qDebug() << "Will delete a formerly active process" << proc;
proc->deleteLater();
}
else /* if (state == QProcess::NotRunning) */
qDebug() << "Ignoring a non-running process" << proc;
});
proc->start(filePath);
}

How can I do that without WIN32 API?

So, here is a countdown.
My aim is the next: if you don't do anything for the given time (ent_sec) the countdown will reach 0 after a time and return with 0, BUT if you press down the letter c (code: 99) the countdown stops and you can enter your PIN code and return with it.
I have already solved the problem with Windows.h in the next way:
if (GetAsyncKeyState(VK_SPACE))
This solves the problem is through WIN32 API (in this case you have to press SPACE, not letter 'c'), but it revealed that I can't use any WinAPI function (school project). So I rewrite this line to the following:
if (getchar() == 99)
But unfortunately it doesn't work in the proper way, cause my countdown stops in almost every second until I dont't press some "wrong" key (for example I press 'x', then the countdown goes forward, but in the next sec it stops again)... In the first solution (win func) this problem doesn't exist... So how can I fix that? Thanks. Here is the whole code of my function:
unsigned Timer::DownCount
{
int ent_sec = this.time;
cout << "The counter has started (" << this.time << "sec), press 'C' to enter your PIN code: " << endl;
while (ent_sec >= 0)
{
if (getchar() == 99) // c letter's code is 99 in ANSI (or ASCII dunno)
{
unsigned code;
cout << "PIN code: ";
cin >> code;
return code;
}
else
{
SecCounter(1); // this function counts 1 secundum
cout << ent_sec << endl;
ent_sec--;
}
}
return 0;
}
I don't believe there's a standard way to do this that will work across all platforms, but here's one way of doing it that will work on Windows without actually using Windows API functions.
int getch_nowait()
{
if (!kbhit()) return -1;
return getch();
}
Then your check just becomes if (getch_nowait() == 99) ...
This code may be compiler specific. If it doesn't work for you, it'll help if you tell us what compiler and operating system you are using.

My program runs but if you compile it closes upon input being placed

Here's the code
Note:I couldn't understand the answers to the other questions
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Input_Program
{
class Program
{
static void Main()
{
char Y = Console.ReadKey().KeyChar;
Console.WriteLine("Welcome to my bool program!");
Console.WriteLine("Input a NON capital y or n when told to.");
if (Y == 'Y')
{
Console.WriteLine("Thank you,Please wait.....");
Console.WriteLine("You input Y");
}
}
}
}
If(You can compile it id appreciate it!)
Simply adding a single line to you existing code will make it wait for another keystroke prior to exiting, this will allow you to see your output at best:
if(Y == 'Y')
{
Console.WriteLine("Thank you,Please wait.....");
Console.WriteLine("You input Y");
}
Console.ReadLine();
An alternative is to run your code within a loop which checks for Q, or exit, or something similar as input, and exit the loop and therefore quitting the application as desired - otherwise just keep processing input.
For instance, you could rearrange your code to look something like this:
Console.WriteLine("Input a NON capital y or n.");
char input;
while((input = Console.ReadKey().KeyChar) != 'n')
{
if(input == 'y')
{
Console.WriteLine("You entered y");
}
}
Console.WriteLine("You entered 'n'");
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
Another answer suggests running through the command-line being an option; while this is possible it would quickly become tedious to have to execute anything outside of your IDE or even anything extra within your IDE if unnecessary - however, you could look into using this practice for deployed console applications, if it never needs to process more than one command or can handle batch commands.
You have 2 options
Running the exe from a command prompt.
Add Console.Readline() as the last line of the Main() function. This will cause your program to wait on the last line of the method until you hit enter.
You're getting the key before you ever prompt for it.
You ask for a NON-capital (lowercase) 'y' or 'n', but compare to a CAPITAL (uppercase) 'Y'.
You're not waiting to see the output before the program exits. Add:
Console.ReadLine();
at the end of Main(), as Naraen said.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Input_Program {
class Program {
static void Main() {
char Y = Console.ReadKey().KeyChar;
Console.WriteLine("Welcome to my bool program!");
Console.WriteLine("Input a NON capital y or n when told to.");
if(Y == 'Y')
{
Console.WriteLine("Thank you,Please wait.....");
Console.WriteLine("You input Y");
}
Console.Readline(); //This will wait for you tu press enter before finishing the program :P
}
}}
Programs that doesn't have graphic interface are closed when the main function is finished, so in this case you don't have time to see what is printed. You could also run it in the command prompt.

Can I suppress selected input before the application's main loop?

As part of my Visual Studio utilities add-in SamTools, I have a mouse input routine that catches Ctrl+MouseWheel and sends a pageup/pagedown command to the active text window. Visual Studio 2010 added a new "feature" that uses that gesture for zoom in/out (barf). Currently, my add-in does send the scrolling command, but Visual Studio still changes the font size because I'm not eating the input.
I set my hook with a call to SetWindowsHookEx. Here's the callback code. My question is: is the best way to prevent Visual Studio from handling the Ctrl+MouseWheel input as a zoom command to simply not call CallNextHookEx when I get a mouse wheel event with the Ctrl key down?
(Please bear in mind this is some old code of mine.) :)
private IntPtr MouseCallback(int code, UIntPtr wParam, ref MOUSEHOOKSTRUCTEX lParam)
{
try
{
// the callback runs twice for each action - this is the latch
if (enterHook)
{
enterHook = false;
if (code >= 0)
{
int x = lParam.mstruct.pt.X;
int y = lParam.mstruct.pt.Y;
uint action = wParam.ToUInt32();
switch (action)
{
case WM_MOUSEWHEEL:
OnMouseWheel(new MouseEventArgs(MouseButtons.None, 0, x, y, ((short)HIWORD(lParam.mouseData)) / (int)WHEEL_DELTA));
break;
default:
// don't do anything special
break;
}
}
}
else
{
enterHook = true;
}
}
catch
{
// can't let an exception get through or VS will crash
}
return CallNextHookEx(mouseHandle, code, wParam, ref lParam);
}
And here's the code that executes in response to the MouseWheel event:
void mouse_enhancer_MouseWheel( object sender, System.Windows.Forms.MouseEventArgs e )
{
try
{
if ( Keyboard.GetKeyState( System.Windows.Forms.Keys.ControlKey ).IsDown && Connect.ApplicationObject.ActiveWindow.Type == vsWindowType.vsWindowTypeDocument )
{
int clicks = e.Delta;
if (e.Delta < 0)
{
Connect.ApplicationObject.ExecuteCommand( "Edit.ScrollPageDown", "" );
}
else
{
Connect.ApplicationObject.ExecuteCommand( "Edit.ScrollPageUp", "" );
}
}
}
catch ( System.Runtime.InteropServices.COMException )
{
// this occurs if ctrl+wheel is activated on a drop-down list. just ignore it.
}
}
PS: SamTools is open source (GPL) - you can download it from the link and the source is in the installer.
PSS: Ctrl+[+] and Ctrl+[-] are better for zooming. Let Ctrl+MouseWheel scroll (the vastly more commonly used command).
According to MSDN, it's possible to toss mouse messages that you process. Here's the recommendation:
If nCode is less than zero, the hook
procedure must return the value
returned by CallNextHookEx.
If nCode is greater than or equal to
zero, and the hook procedure did not
process the message, it is highly
recommended that you call
CallNextHookEx and return the value it
returns; otherwise, other applications
that have installed WH_MOUSE hooks
will not receive hook notifications
and may behave incorrectly as a
result. If the hook procedure
processed the message, it may return a
nonzero value to prevent the system
from passing the message to the target
window procedure.
In other words, if your mouse callback ends up using the mouse message, you don't have to call the next CallNextHookEx -- just return a nonzero value and (in theory, at least) the mouse movement should get swallowed. If that doesn't work the way you want, comment and we can iterate.
BTW, another possible alternative: it's possible that VS's mapping to the mouse wheel shows up in the Tools...Customize... UI, just like key mappings do. In that case, you could simply remap your add-in's commands instead of working at the hook level. But it's also posible (likely?) that this gesture is hard-coded.

Resources