How to tell if user has released slider - godot

There's an issue on the github to add a released() signal to the slider node, but how would I do the same thing without it?
I want to have a slider, and when the user moves it it says "Value is now X" on a label on the screen. But when I do it based on the 'value_changed(x)' it calls many times while the slider is being dragged. I want it to set my only label when the player releases after sliding, or when presses and releases an area on the slider's range to select a new value without using the grabber.

Okay, this is what I've come up with. It doesn't literally let me know when the slider is released, but it tells me when the player stops editing the slider. It still sends an alert if you pause briefly, but that is okay for my game. It doesn't send continuous alerts like if you just use _on_HSlider_value_changed(), which is what I wanted to avoid.
var old = self.value #start value of slider
var timer_on = false
#will be called continuously while editing timer
func editing_slider(new):
#only start a timer, if there isn't one already or you'll have a million
if not timer_on:
#start timer
timer_on = true
yield(get_tree().create_timer(.2), "timeout" )
timer_on = false
#if still editing, re call function
if old != new:
editing_slider(new)
#done editing
else:
print("slider set to " + str(value))
old = new
func _on_HSlider_value_changed(value):
editing_slider(value)
If you wanted to avoid the alert being called when the user pauses but hasn't released, you'd have to do do some kind of InputEvent check.

You can achieve what you want by overriding the _gui_input function. Attach a script to your slider, and then add this code:
func _gui_input(event):
if (event is InputEventMouseButton) && !event.pressed && (event.button_index == BUTTON_LEFT):
print("Released")
This will work whether the user releases the grabber or "releases an area on the slider's range to select a new value without using the grabber", and achieves what you want. However, if the code is meant to run on a device with a keyboard (e.g. a PC), then the user can also change the value via the cursor keys on the keyboard, and you may want to add support for that too.

Related

Can't update GtkIconView from within a click event on a GtkListBox in a GtkDialog

Here's what the click event currently looks like for the ListBox in the dialog code.
def OnSelectCategory(self, listbox, data=None):
try:
# Get the text of the selected category.
selected = listbox.get_selected_row()
label = selected.get_child()
itemText = label.get_text()
# Get the tags for the selected category.
tagtext = self.categoryTags.get(itemText)
self.updateStatusbar("Collecting videos...")
# Start a thread to scan for videos.
self.threadEvent = threading.Event()
self.videoscanThread = threading.Thread(target=self.ScanForVideos, args=(self.threadEvent, tagtext,))
self.videoscanThread.daemon = True
self.videoscanThread.start()
self.threadEvent.set()
except Exception as e:
print("Exception from 'OnSelectCategory':", str(e))
At first, I could not get the status bar to update the text immediately. I had originally called the function to update the text directly. The status bar text would not update until the ScanForVideos function had finished. So, I moved the ScanForVideos code into a thread. The thread waits on an event to begin.
The thread (ScanForVideos) runs several 'for' loops looking for a matching condition. When the condition is found, the code appends to the liststore for the IconView. At the end of the thread function, the code sets the IconView model to the liststore. The IconView seems to update with a few items, but, not all that should be there. Additionally, the code seems to be 'hung' because I cannot dismiss the dialog that contains the IconView. I have to stop debugging within Visual Studio Code.
I feel like I'm violating something I'm not aware of in Python coding. Or, my design to update the IconView is not correct. Can anyone shed some light on what I may be doing wrong?
I realized that I was trying to update some UI widgets from within my background thread. I then stumbled upon GLib.idle_add. I wrote a separate function to update the UI widgets and called idle_add passing the name of the function. This allowed me to update the GUI from a background thread.

Control close event pyglet

I have a program that has multiple windows in pyglet, and I want to make one window unclosable, rather to set its visibility to false. Is there a way I can access the event handle for close, to make it instead of closing the window, possibly return a bool or a string like "should close."?
Found the answer to my own question, first define a custom event loop with window_event_loop = pyglet.app.EventLoop(), then create a handler for .event for the event loop
#window_event_loop.event
def on_window_close(window):
# Extra code here
return pyglet.event.EVENT_HANDLED

PyQt5 UI stuck at long operation

I'm creating a game with some AI that may take some time. The problem is even if I call relevant methods to update the UI before running the AI function, the UI is not visually updated.
Some example code looks like this
def onClickBoard(self, e):
x, y = toBoardGrid(e.x(), e.y())
self.game.move(x, y)
self.update_board()
print("before AI")
# This line takes a few seconds
ai_move = self.ai.get_best_move(self.game)
print("after AI")
self.game.move(ai_move[0], ai_move[1])
self.update_board()
Where self.update_board is a method that updates a QWidget and it's very fast. This onClickBoard method is assigned to the widget's mouseReleaseEvent.
self.board.mouseReleaseEvent = self.onClickBoard
When running the game, I can see before AI printed to the terminal but the visual window doesn't change. I see the window updates only once, after the AI commits its move.
Is there a way to make the board update once before the slow function call and another once after it?
Yes, you can force Qt to process all pending events, and thus update the GUI, with the QApplication::processEvents() method. Add the following line just before the slow function call:
QtWidgets.QApplication.instance().processEvents()

Linux x11 XGrabKeyboard() cause keyboard to be frozen

I am writing a program which need to listen the user keyboard stroks.
I use function XGrabKeyboard() and this is my code:
XGrabKeyboard(pDisplay, DefaultRootWindow(pDisplay), True, GrabModeAsync, GrabModeAsync, CurrentTime);
XEvent event;
while (true)
{
XNextEvent(pDisplay, &event);
switch (event.type)
{
...
}
}
But it causes the keyboard and cursor to be frozen.
I looked up the man page, it only says: "The third parameter specifies a Boolean value that indicates whether the keyboard events are to be reported as usual."
I tried both true or false or the 3rd param, both GrabModeAsync and GrabModeSync for the 4th and 5th param, but it doesn't work.
After calling XGrabKeyboard(), the keyboard is frozen and mouse click doesn't response.
Any ideas?
XGrabKeyboard() (if successful - be sure to check the return value), redirects all key events to your client.
So if your "..." inside the while(true) does not properly handle those key events, or does not ever ungrab (XUngrabKeyboard) or release sync events (XAllowEvents, only applies to GrabModeSync), then the keyboard would appear to lock up.
The boolean parameter is owner_events which indicates whether to report key events always to the window provided to XGrabKeyboard, or report them to the window they normally would have gone to without the grab. Typically you want False (report to the grab window).
For typical uses of XGrabKeyboard (I don't know your use-case) the parameters you would want are:
grab window = some window in your app that relates to the reason for the grab
owner_events=False to send all events to that window
pointer_mode=Async to not screw with the pointer
keyboard_mode=Async to just redirect all key events and avoid need for AllowEvents
time=the timestamp from the event triggering the grab, ideally, or one generated by changing a property and grabbing the timestamp off the PropertyNotify
But, it depends. To give any definitive answer you'd probably need to post a compilable program, I think the bug is likely in the "..." part of your code. Try narrowing your app down to a single-file test case that can be run by others perhaps. Or explain more why you are grabbing and what you're trying to accomplish in the big picture.
I cant help with the XGrabKeyboard function - I havent used it before and dont know how it works - but I can suggest another way of getting the keyboard events.
When creating my window using XCreateWindow, the last argument is a XSetWindowAttributes object. This object has a member event_mask, which you can use to choose which events your window will receive.
I set mine like this:
XSetWindowAttributes setWindAttrs
setWindAttrs.event_mask = ExposureMask
| KeyPressMask
| KeyReleaseMask
| ButtonPressMask
| ButtonReleaseMask;
That will mean you receive events for keyboard key presses and mouse button clicks if you pass this object to XCreateWindow on window creation.
Also another note you can use XPending(pDisplay) to check if there are still events waiting to be handled - so it could replace true in your while(true) line.
Edit: Also your freezing issue could be that you dont return false anywhere in your while loop? It may be stuck in an infinite loop, unless you just removed that bit for the post. Try replacing true with xpending as I suggested above and it may fix the issue, or just returning false after handling the event, but this would only handle one event per frame rather than handling all the currently pending events like XPending would do, and I assume that is what you want to do.

specific motion tween stop & resume

I'm new in games development, am trying to create a simple game in flash-cs5. I created 3 motion tweens in timeline. i'm trying to stop a specific motion tween, when that tween's movieclip is clicked while other tweeens are running and also when the stopped movieclip is clicked again i want to resume the tween while other tweeens are running.
thanking in advanced.
The following is assuming you have each motion tween inside its own movieclip. I am not aware of any method of stopping one tween while leaving the other playing on a single movieclip (or if they are each on the main stage).
That said, you can stop and start animations fairly easily. Below is an example of how to stop a motion tween where it is in playback, and then resume it from that point.
In the example, "myMovieClip" is the movie clip we're working with. We're going to leave the rest of the movieclips alone, as they'll keep playing on their own. I'm also assuming that myMovieClip is playing by default.
The following is in AS3. Place it on the Actions panel for your main stage (first frame if you have multiple frames.)
Also, ensure you have named your MovieClip. To do this, click the MovieClip on your stage in design mode, and then click Properties. There should be a text entry box towards the box. Write the name you want for your MovieClip there.
//Declare a boolean variable that determines whether or not the movieclip timeline is playing.
var ClipPlaying:Boolean = true;
//Add the mouse click event listener to the movie clip.
myMovieClip.addEventListener(MouseEvent.CLICK, StopOrStartClip);
//Declare the function for the above event listener.
function StopOrStartClip(evt:MouseEvent):void
{
//Switch statements are my personal favorites...they're more streamlined than if statements.
switch(ClipPlaying)
{
//If the clip is playing it, we stop it and set ClipPlaying to false.
case true:
myMovieClip.stop();
ClipPlaying = false;
break;
//If the clip is not playing, we start it and set ClipPlaying to true.
case false:
myMovieClip.play();
ClipPlaying = true;
break;
}
}
The most important functions to remember here are:
myMovieClip.stop();
This freezes your animation at its current position.
myMovieClip.play();
This resumes your animation playback from its current position.
When you use either, remember to replace "myMovieClip" with the name of your movie clip!
By the way, slightly unrelated, I highly recommend the book ActionScript 3.0 Game Programming University to learn how to create Flash games.
You wouldn't actually need 5 different event listeners, or functions, or variables; you could just make one function to handle it all:
stage.addEventListener(MouseEvent.CLICK, stageClick);
function stageClick(event:MouseEvent):void {
//I prefer "if" statements
if (event.target == myMovieClip1) stuff here;
else if (event.target == myMovieClip2) stuff here;
else if (event.target == myMovieClip3) stuff here;
else if (event.target == myMovieClip4) stuff here;
else if (event.target == myMovieClip5) stuff here;
}
I can add more details if needed, but this question was from three years ago so probably not.

Resources