Abort a QCloseEvent - qt5

In my application, I am handling a QCloseEvent (when the close button X was pressed):
void MainWindow::closeEvent(QCloseEvent* event)
{
if ( !isAbortedFilestoSave() ) {
this->close();
}
// else abort
}
The if clause is triggereed when no abort was pressed. I would like to implement an else clause where a QCloseEvent is aborted? How?

You must use the ignore() on the event to "abort it" - to let Qt know you don't want the widget to actually close.
The isAccepted() function returns true if the event's receiver has agreed to close the widget; call accept() to agree to close the widget and call ignore() if the receiver of this event does not want the widget to be closed.
Also, no need to call close() yourself - the "X" button does that already, that's why you receive a close event!
So your code should be:
void MainWindow::closeEvent(QCloseEvent* event)
{
// accept close event if are not aborted
event->setAccepted(!isAbortedFilestoSave());
}

Related

Suspend `withTimeout`

My app starts from executing coroutine:
model.viewModelScope.launch(Dispatchers.IO) {
val timeout = withTimeoutOrNull(TIMEOUT) {
//send some initialization server requests
true //timeout=true
}
if (timeout!=null){
// app started ok
} else {
// app freezed on start
}
}
The problem is one of the initialization step - obtain user consent to share his personal data(GDPR) Consent form is a modal popup that waits for user input.But the timer is ticking all this time. Therefore after gdpr user may see app starts too long error.
Is there way to suspend withTimeoutOrNull timer and resume it after some time?
It is not supported out of the box, but you can write your own version of withTimeoutOrNull that would support a pauseable timer. The key idea is to run your block in a separate coroutineScope { ... } and to launch a secondary helper coroutine that would cancel this scope after timeout. Now if you keep a reference to this helper cancellationJob, then you can cancel it when you need to pause your time and restart it when you need to resume timer.
That would give you essentially the same behavior that basic withTimeout has but with an added pauseability. A bit of extra code is needed to implement a withTimeoutOrNull variant. You'll need to catch your cancellation exception and replace it with null result.
A worked-out implementation can be found in this gist: https://gist.github.com/elizarov/c5b0fde43ca14efbb8bcab13ad43c6ca

Is there a way wait for code to take effect before a "notify" method is called (E.G. notifyItemRangeInserted) on a Recycler view?

I want to show a progress dialog screen in my app whenever a recycler view begins to load more items. The problem is: I can't get to show the dialog screen because the notify method is ALWAYS executed (and freezes the screen) before the loading screen shows up. Happens even if the "show()" method for it is called in the very first line of my "addContacts()" method.
I've already tried:
getActivity().runOnUiThread();
creating a Thread, starting it, calling join()
starting it with executors
public void addContactsToScreen() {
((BaseActivity) lcf.getActivity()).showProgressDialog();
try {
int currentSize = contactsLoaded.size();
int inserted;
for (inserted = 0;
inserted < DEFAULT_ITEM_INSERTION
&& inserted < lcf.getController().getContacts().size()
&& contactsLoaded.size() < lcf.getController().getContacts().size()
; inserted++) {
contactsLoaded.add(lcf.getController().getContacts().get(currentSize + inserted));
}
if (inserted > 0) {
notifyItemRangeInserted(contactsLoaded.size() - 1, inserted);
}
lcf.getContactsRecycler().getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
lcf.isLoading=false;
lcf.getContactsRecycler().post(new Runnable() {
#Override
public void run() {
((BaseActivity) lcf.getActivity()).hideProgressDialog();
}
});
lcf.getContactsRecycler().getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
That is the original code (no threads or failed attempts). The void is called everytime I initialize the adapter or the view reaches a threshold limit. It loads a list that ends up being shown on screen after "notifyItemRangeInserted()" is called. As you can see the VERY FIRST LINE tries to show the loading screen but for some reason, in the debugger itself I find with breakpoints that the method calls the show method, but the loading screen never appears, fills the list in the "for" loop, calls the notify event, the screen freezes, THEN the loading screen finally shows up but then immediately the hide method is called (rendering teh loading screen useless)
Did you try post runnable method?
progressbar.setvisibility(view.visible);
progressbar.post(new Runnable() {
#Override
public void run() {
fetchMoreDataInTheRecyclerView();
}
});
*Now do the fetching inside fetchMoreDataInTheRecyclerView(); and once done simply make progressbar invisible.
Let me know if this helps.

How to force a libusb event so that libusb_handle_events() returns

Suppose I have a libusb program that just uses the hotplug API. You register a callback and then apparently have to call libusb_handle_events() in a loop which then calls your hotplug callback.
int LIBUSB_CALL hotplugCallback(libusb_context* ctx,
libusb_device* device,
libusb_hotplug_event event,
void* user_data)
{
cout << "Device plugged in or unplugged";
}
void main()
{
libusb_init(nullptr);
libusb_hotplug_register_callback(nullptr,
static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
LIBUSB_HOTPLUG_NO_FLAGS,
LIBUSB_HOTPLUG_MATCH_ANY,
LIBUSB_HOTPLUG_MATCH_ANY,
LIBUSB_HOTPLUG_MATCH_ANY,
&hotplugCallback,
this,
&hotplugCallbackHandle);
for (;;)
{
if (libusb_handle_events_completed(nullptr, nullptr) != LIBUSB_SUCCESS)
return 1;
}
return 0;
}
The question is, without timeout hacks how can I exit this event loop cleanly? I can't find any functions that force libusb_handle_events() (or libusb_handle_events_completed()) to return. In theory they could just never return.
Sorry if this is late.
The question could have been phrased better but I'm assuming (from your comment updates) that your actual program resembles something a little closer to this:
int LIBUSB_CALL hotplugCallback(libusb_context *ctx,
libusb_device *device,
libusb_hotplug_event event,
void *user_data) {
cout << "Device plugged in or unplugged";
}
void SomeClass::someFunction() {
libusb_init(nullptr);
libusb_hotplug_register_callback(nullptr,
static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
LIBUSB_HOTPLUG_NO_FLAGS,
LIBUSB_HOTPLUG_MATCH_ANY,
LIBUSB_HOTPLUG_MATCH_ANY,
LIBUSB_HOTPLUG_MATCH_ANY,
&hotplugCallback,
this,
&hotplugCallbackHandle);
this->thread = std::thread([this]() {
while (this->handlingEvents) {
int error = libusb_handle_events_completed(context, nullptr);
}
});
}
Let's say your object is being deallocated and, no matter what is happening on the USB bus, you don't care and you want to clean up your thread.
You negate this->handlingEvents and you call thread.join() and the thread hangs for 60 seconds and then execution resumes.
This is done because the default behavior of libusb_handle_events_completed calls libusb_handle_events_timeout_completed and passes in a 60 second timeout interval with plans to make it infinite.
The way you force libusb_handle_events_completed to return is you call libusb_hotplug_deregister_callback which wakes up libusb_handle_events(), causing the function to return.
There is more info about this behavior in the docs.
So your destructor (or wherever you want to stop listening immediately) for the class could look something like this:
SomeClass::~SomeClass() {
this->handlingEvents = false;
libusb_hotplug_deregister_callback(context, hotplugCallbackHandle);
if (this->thread.joinable()) this->thread.join();
libusb_exit(this->context);
}
In the function:
int libusb_handle_events_completed(libusb_context* ctx, int* completed)
You can change the value of the completed to "1" so the function will return without blocking
According to their docs:
If the parameter completed is not NULL then after obtaining the event
handling lock this function will return immediately if the integer
pointed to is not 0. This allows for race free waiting for the
completion of a specific transfer.
There is no functions in libusb that force libusb_handle_events() to return.
It's recommended to use libusb_handle_events() in a dedicated thread so your main thread will not be blocked by this call. Even though, if you need to manipulate the call of the event handler you can put the call in a while(condition) and change the condition state in your main thread.
Libusb documentation details this here.

How to loop while() on a form application

I want to create a loop in my windowform application in C++/CLI.
I have the following button:
private: System::Void button17_Click(System::Object^ sender, System::EventArgs^ e) {
this->button17->ForeColor = System::Drawing::Color::Lime;
while (true) {
if (button17->Enabled == true) {
HWND hwnd1;
hwnd1 = FindWindow(NULL, "1");
}
else {
break;
}
} /// End while
}
I created a button with a while() statement. When I press the 'on' button, the loop should execute, and when I press this button again, the loop should end, and the program should stop this while statement.
However, when I press my button, the program does what I want, but my application suspends and can't do anything. What am I doing wrong, and how can make a loop when I press a button, and stop the loop when I press the button again?
C++/CLI is not "just C++". It is for writing code to interface C# or other .Net languages to C++ code. If you want to write "just C++", make a C++ project and use MFC for the GUI.
In any language, the answer is this: A while loop in a button handler will cause the UI thread to be busy with the while loop, and not with such things as redrawing the UI or responding to the subsequent button push. For this, I'd start a background thread at program load, and use a synchronization object to trigger whether the thread is doing work or not.
You are blocking your current thread.
You need to take this loop and put it in a thread. Then launch the thread to run in the background.
while (true) {
if (button17->Enabled == true) {
HWND hwnd1;
hwnd1 = FindWindow(NULL, "1");
}
else {
break;
}
} /// End while

Global Hotkey eventNotHandledErr Pass to Event Handler

I've pored through most of the posts regarding the creation of Global Hotkeys using Carbon. Is it possible in the hot key handler function to return eventNotHandledErr and have the event passed on to the next handler? Here's some pseudocode:
OSStatus myHotKeyHandler(EventHandlerCallRef nextHandler, EventRef anEvent, void *userData)
{
OSStatus result;
if ( appX is running || appY is running ) {
[(MyAppController *) userData doSomething];
result = noErr;
} else {
result = eventNotHandledErr;
}
return result;
}
In the event that I'm not in application X or Y, I want to be able to pass the event on. Is this possible?
I know I can set up a notification for application switched events, but that requires Enable access for assistive devices to be turned on. If there's a way to pass the event to the next handler, that would be great.