有没有办法在 Gtk window/widget 中停用鼠标光标?
Is there a way to deactivate mouse cursor in Gtk window/widget?
我的第一个问题是:有没有一种方法可以简单地停用小部件或所有 window 中的鼠标光标?
现在问题的背景:
我正在编写一个要在其中显示视频的应用程序。播放视频时,我使用键盘快捷键来显示和隐藏进度,也可以暂停。到目前为止,一切正常,除了当我的鼠标光标位于 window 时,按键事件的 none 不再起作用。使它们再次工作的唯一方法是手动将光标移出 window。
我宁愿不必手动移动光标,而且您视频中的箭头也很烦人。这就是我问这个问题的原因。
这是一个代码示例:
import pafy, gi
gi.require_versions({'Gtk':'3.0', 'GdkX11':'3.0', 'Gst':'1.0', 'GstVideo':'1.0'})
from gi.repository import Gst, Gtk, GLib, GdkX11, GstVideo, GObject
vertical = Gtk.Orientation.VERTICAL
horizontal = Gtk.Orientation.HORIZONTAL
link = #PLZ insrte here any youtube video link
vid = pafy.new(link)
best = vid.getbest()
uri = best.url
class GstWidget(Gtk.DrawingArea):
def __init__(self):
super().__init__()
self.connect('draw', self.on_draw)
self.connect('realize', self.on_realize)
self.connect('unrealize', self.on_unrealize)
# Create GStreamer pipeline
self.pipeline = Gst.Pipeline()
# Create bus to get events from GStreamer pipeline
self.bus = self.pipeline.get_bus()
self.bus.add_signal_watch()
self.bus.connect('message::eos', self.on_eos)
self.bus.connect('message::error', self.on_error)
# This is needed to make the video output in our DrawingArea:
self.bus.enable_sync_message_emission()
self.bus.connect('sync-message::element', self.on_sync_message)
# Create GStreamer elements
self.playbin = Gst.ElementFactory.make('playbin', None)
# Add playbin to the pipeline
self.pipeline.add(self.playbin)
# Set properties
self.playbin.set_property('uri', uri)
def on_realize(self, widget, data=None):
print("on_relalize")
window = widget.get_window()
self.xid = window.get_xid()
def on_draw(self, widget, cr):
if self.playbin.get_state(0).state < Gst.State.PAUSED:
allocation = widget.get_allocation()
cr.set_source_rgb(0, 0, 0)
cr.rectangle(0, 0, allocation.width, allocation.height)
cr.fill()
# self.on_realize(widget)
def on_unrealize(self, widget, data=None):
# to prevent racing conditions when closing the window while playing
self.playbin.set_state(Gst.State.NULL)
self.pipeline.set_state(Gst.State.NULL)
def on_sync_message(self, bus, msg):
if msg.get_structure().get_name() == 'prepare-window-handle':
print('prepare-window-handle')
print('on_sync', self.xid)
self.playbin.set_window_handle(self.xid)
print(msg)
print(msg.src)
def on_eos(self, bus, msg):
self.pipeline.seek_simple(
Gst.Format.TIME,
Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT,
0
)
def on_error(self, bus, msg):
err, debug = message.parse_error()
print(f"Error: {err}", debug)
class Master(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Gst_test")
button = Gtk.Button(label="Play")
button.connect("clicked", self.on_button_clicked)
self.add(button)
def on_button_clicked(self, widget):
for child in self.get_children():
child.destroy()
self.video_player = GstWidget()
#main container
self.main_box = Gtk.Box(orientation=vertical)
#for the progress bar
self.hbox = Gtk.Box(orientation=horizontal)
#here we gona make our progressbar.
self.slider = Gtk.Scale.new_with_range(horizontal, 0, 100, 0.5)
# self.slider_handler_id = self.slider.connect("value-changed", self.on_slider_seek)
self.hbox.pack_start(self.slider, True, True, 2)
self.main_box.pack_start(self.video_player, True, True, 0)
self.add(self.main_box)
# set focus on the main_box and connect it to the key_pressed method
self.main_box.set_can_focus(True)
self.main_box.grab_focus()
self.main_box.connect("key-press-event", self.key_pressed)
self.show_all()
#adding the progress bare after the show_all so we don't have it by default
self.main_box.pack_start(self.hbox, False, False, 0)
if self.video_player.playbin.get_state(0).state != Gst.State.PAUSED:
self.video_player.pipeline.set_state(Gst.State.PLAYING)
else:
self.video_player.pipeline.set_state(Gst.State.PAUSED)
def key_pressed(self, widget, event):
#is the pressed key the up-arrow?
if event.get_keyval()[1] == 65362:
self.show_all()
#is the pressed key the down-arrow?
elif event.get_keyval()[1] == 65364:
self.hbox.hide()
#is key F11?
elif event.get_keyval()[1] == 65480:
print(f"{self.is_fullscreen=}")
#is the pressed key the space-bar?
elif event.get_keyval()[1] == 32:
if self.video_player.playbin.get_state(0).state == Gst.State.PLAYING:
self.video_player.pipeline.set_state(Gst.State.PAUSED)
self.show_all()
else:
if self.video_player.playbin.get_state(0).state == Gst.State.PAUSED:
self.video_player.pipeline.set_state(Gst.State.PLAYING)
self.hbox.hide()
#if it is any of the previous, just tell me which is.
else:
print(f"{__name__=} @ line 160, {event.get_keyval()}")
if __name__ == "__main__":
Gst.init(None)
root = Master()
root.connect("delete-event", Gtk.main_quit)
root.show_all()
Gtk.main()
我在寻找答案时尝试使用斜杠:我在 documentations 中搜索过,但我还没有找到如何做到这一点,在 Gtk 中没有,在 Gdk 中没有,在 Gst 中没有。我在网上发现了一些关于 Gst Navigate 的文章,但是它是用 C 写的,我从来没有学过它,所以它对我没有帮助。 "navigate" 它不在我刚刚链接的文档中。
我还在 Whosebug here 中发现了一些问题,但它已经 5 岁了,现在似乎不起作用了。 Gtk.Gdk.Pixmap 似乎不能用了。或者用其他名字?
感谢您的宝贵时间
Question: deactivate mouse cursor in Gtk window/widget?
这与将 new/different Cursor
设置为小部件相同。
您必须等待 realize
信号。
如果小部件的 Gdk.Window
尚未创建,则无法更改光标。
- Gtk.Widget.get_display
- Gdk.Cursor.new_for_display, Gdk.Cursor.new_from_name
- Gtk.Widget.get_window
- Gdk.Window.set_cursor
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GLib
class ApplicationWindow(Gtk.ApplicationWindow):
def __init__(self):
super().__init__()
self.connect("destroy", Gtk.main_quit)
self.set_size_request(100, 70)
self.connect("realize", self.on_realize)
GLib.timeout_add(interval=5000, function=self.reset_cursor)
def on_realize(self, widget):
# Step 1: Get the Gdk.Display for the toplevel for this widget.
display = widget.get_display()
# Step 2: Create a new Cursor of type BLANK_CURSOR
cursor = Gdk.Cursor.new_for_display(display, Gdk.CursorType.BLANK_CURSOR)
# Step 3: Get the widget’s Gdk.Window and set the new Cursor
widget.get_window().set_cursor(cursor)
def reset_cursor(self):
cursor = Gdk.Cursor.new_from_name(self.get_display(), 'default')
self.get_window().set_cursor(cursor)
if __name__ == "__main__":
ApplicationWindow()
Gtk.main()
测试 Python:3.5 - gi.__version__:3.22.0
我的第一个问题是:有没有一种方法可以简单地停用小部件或所有 window 中的鼠标光标? 现在问题的背景:
我正在编写一个要在其中显示视频的应用程序。播放视频时,我使用键盘快捷键来显示和隐藏进度,也可以暂停。到目前为止,一切正常,除了当我的鼠标光标位于 window 时,按键事件的 none 不再起作用。使它们再次工作的唯一方法是手动将光标移出 window。 我宁愿不必手动移动光标,而且您视频中的箭头也很烦人。这就是我问这个问题的原因。
这是一个代码示例:
import pafy, gi
gi.require_versions({'Gtk':'3.0', 'GdkX11':'3.0', 'Gst':'1.0', 'GstVideo':'1.0'})
from gi.repository import Gst, Gtk, GLib, GdkX11, GstVideo, GObject
vertical = Gtk.Orientation.VERTICAL
horizontal = Gtk.Orientation.HORIZONTAL
link = #PLZ insrte here any youtube video link
vid = pafy.new(link)
best = vid.getbest()
uri = best.url
class GstWidget(Gtk.DrawingArea):
def __init__(self):
super().__init__()
self.connect('draw', self.on_draw)
self.connect('realize', self.on_realize)
self.connect('unrealize', self.on_unrealize)
# Create GStreamer pipeline
self.pipeline = Gst.Pipeline()
# Create bus to get events from GStreamer pipeline
self.bus = self.pipeline.get_bus()
self.bus.add_signal_watch()
self.bus.connect('message::eos', self.on_eos)
self.bus.connect('message::error', self.on_error)
# This is needed to make the video output in our DrawingArea:
self.bus.enable_sync_message_emission()
self.bus.connect('sync-message::element', self.on_sync_message)
# Create GStreamer elements
self.playbin = Gst.ElementFactory.make('playbin', None)
# Add playbin to the pipeline
self.pipeline.add(self.playbin)
# Set properties
self.playbin.set_property('uri', uri)
def on_realize(self, widget, data=None):
print("on_relalize")
window = widget.get_window()
self.xid = window.get_xid()
def on_draw(self, widget, cr):
if self.playbin.get_state(0).state < Gst.State.PAUSED:
allocation = widget.get_allocation()
cr.set_source_rgb(0, 0, 0)
cr.rectangle(0, 0, allocation.width, allocation.height)
cr.fill()
# self.on_realize(widget)
def on_unrealize(self, widget, data=None):
# to prevent racing conditions when closing the window while playing
self.playbin.set_state(Gst.State.NULL)
self.pipeline.set_state(Gst.State.NULL)
def on_sync_message(self, bus, msg):
if msg.get_structure().get_name() == 'prepare-window-handle':
print('prepare-window-handle')
print('on_sync', self.xid)
self.playbin.set_window_handle(self.xid)
print(msg)
print(msg.src)
def on_eos(self, bus, msg):
self.pipeline.seek_simple(
Gst.Format.TIME,
Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT,
0
)
def on_error(self, bus, msg):
err, debug = message.parse_error()
print(f"Error: {err}", debug)
class Master(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Gst_test")
button = Gtk.Button(label="Play")
button.connect("clicked", self.on_button_clicked)
self.add(button)
def on_button_clicked(self, widget):
for child in self.get_children():
child.destroy()
self.video_player = GstWidget()
#main container
self.main_box = Gtk.Box(orientation=vertical)
#for the progress bar
self.hbox = Gtk.Box(orientation=horizontal)
#here we gona make our progressbar.
self.slider = Gtk.Scale.new_with_range(horizontal, 0, 100, 0.5)
# self.slider_handler_id = self.slider.connect("value-changed", self.on_slider_seek)
self.hbox.pack_start(self.slider, True, True, 2)
self.main_box.pack_start(self.video_player, True, True, 0)
self.add(self.main_box)
# set focus on the main_box and connect it to the key_pressed method
self.main_box.set_can_focus(True)
self.main_box.grab_focus()
self.main_box.connect("key-press-event", self.key_pressed)
self.show_all()
#adding the progress bare after the show_all so we don't have it by default
self.main_box.pack_start(self.hbox, False, False, 0)
if self.video_player.playbin.get_state(0).state != Gst.State.PAUSED:
self.video_player.pipeline.set_state(Gst.State.PLAYING)
else:
self.video_player.pipeline.set_state(Gst.State.PAUSED)
def key_pressed(self, widget, event):
#is the pressed key the up-arrow?
if event.get_keyval()[1] == 65362:
self.show_all()
#is the pressed key the down-arrow?
elif event.get_keyval()[1] == 65364:
self.hbox.hide()
#is key F11?
elif event.get_keyval()[1] == 65480:
print(f"{self.is_fullscreen=}")
#is the pressed key the space-bar?
elif event.get_keyval()[1] == 32:
if self.video_player.playbin.get_state(0).state == Gst.State.PLAYING:
self.video_player.pipeline.set_state(Gst.State.PAUSED)
self.show_all()
else:
if self.video_player.playbin.get_state(0).state == Gst.State.PAUSED:
self.video_player.pipeline.set_state(Gst.State.PLAYING)
self.hbox.hide()
#if it is any of the previous, just tell me which is.
else:
print(f"{__name__=} @ line 160, {event.get_keyval()}")
if __name__ == "__main__":
Gst.init(None)
root = Master()
root.connect("delete-event", Gtk.main_quit)
root.show_all()
Gtk.main()
我在寻找答案时尝试使用斜杠:我在 documentations 中搜索过,但我还没有找到如何做到这一点,在 Gtk 中没有,在 Gdk 中没有,在 Gst 中没有。我在网上发现了一些关于 Gst Navigate 的文章,但是它是用 C 写的,我从来没有学过它,所以它对我没有帮助。 "navigate" 它不在我刚刚链接的文档中。
我还在 Whosebug here 中发现了一些问题,但它已经 5 岁了,现在似乎不起作用了。 Gtk.Gdk.Pixmap 似乎不能用了。或者用其他名字?
感谢您的宝贵时间
Question: deactivate mouse cursor in Gtk window/widget?
这与将 new/different Cursor
设置为小部件相同。
您必须等待 realize
信号。
如果小部件的 Gdk.Window
尚未创建,则无法更改光标。
- Gtk.Widget.get_display
- Gdk.Cursor.new_for_display, Gdk.Cursor.new_from_name
- Gtk.Widget.get_window
- Gdk.Window.set_cursor
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GLib
class ApplicationWindow(Gtk.ApplicationWindow):
def __init__(self):
super().__init__()
self.connect("destroy", Gtk.main_quit)
self.set_size_request(100, 70)
self.connect("realize", self.on_realize)
GLib.timeout_add(interval=5000, function=self.reset_cursor)
def on_realize(self, widget):
# Step 1: Get the Gdk.Display for the toplevel for this widget.
display = widget.get_display()
# Step 2: Create a new Cursor of type BLANK_CURSOR
cursor = Gdk.Cursor.new_for_display(display, Gdk.CursorType.BLANK_CURSOR)
# Step 3: Get the widget’s Gdk.Window and set the new Cursor
widget.get_window().set_cursor(cursor)
def reset_cursor(self):
cursor = Gdk.Cursor.new_from_name(self.get_display(), 'default')
self.get_window().set_cursor(cursor)
if __name__ == "__main__":
ApplicationWindow()
Gtk.main()
测试 Python:3.5 - gi.__version__:3.22.0