I'm pretty new to OOP and gtk programming, so sorry if the answer my question is really obvious, but I can't find a solution. I am trying to make a browser-like interface using the Gtk notebook. I wrote a method to add tabs, and it seems to work, becasue when I call it in the init, it works, and adds a new tab. Here the method is:
def create_page(self, button):
print("creating a new page")
print(self)
self.newpage = Gtk.Box()
self.newpage.set_border_width(50)
self.newpage.add(Gtk.Label.new("add notes here"))
self.notebook.append_page(self.newpage, Gtk.Label.new("new page"))
The reason the method has to have the button parameter is becasue I want it to be called by a button, and for that to happen, it has to have a button parameter.
When the button calls the parameter, the print statment works, and it prints its self <main.MyWindow object at 0x7efd64e52a80 (main+MyWindow at 0xe60270)>. It prints the exact same output as when I call it from the init.The problem is that it never actually adds the new notebook tab for some reason. Here my full code is:
import gi
# Since a system can have multiple versions
# of GTK + installed, we want to make
# sure that we are importing GTK + 3.
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title ="Stickies Hub")
#self.set_border_width(70)
# Create Notebook
self.notebook = Gtk.Notebook.new()
self.add(self.notebook)
#create buttons
self.new_tab = Gtk.Button(label=("button"))
self.new_tab.connect("clicked", self.create_page)
# Create pages
self.page1 = Gtk.Box()
self.page1.set_border_width(50)
self.page1.add(Gtk.Label.new("Welcome to Geeks for Geeks"))
self.notebook.append_page(self.page1, Gtk.Label.new("Click Here"))
self.page2 = Gtk.Box()
self.page2.set_border_width(50)
self.page2.add(Gtk.Label.new("A computer science portal for geeks"))
self.page2.add(self.new_tab)
self.notebook.append_page(self.page2, Gtk.Label.new("Click Here"))
self.create_page(self.new_tab)
self.create_page(self.new_tab)
def create_page(self, button):
print("creating a new page")
print(self)
self.newpage = Gtk.Box()
self.newpage.set_border_width(50)
self.newpage.add(Gtk.Label.new("new page"))
self.notebook.append_page(self.newpage, Gtk.Label.new("new page"))
win = MyWindow()
win.connect("destroy", Gtk.main_quit)
# Display the window.
win.show_all()
# Start the GTK + processing loop
Gtk.main()
How can I add a new notebook tab from a button?
Thanks so much for help!
As jackw11111 said, the solution was to add self.show_all() at the end of create_page function. Thanks so much!
I made an answer so anyone with this same problem could easily find the answer.
Helloo, Here is my code. I think this will work for you.
from gi.repository import Gdk
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class MyWindow(Gtk.Window):
notebook = Gtk.Notebook()
def __init__(self):
Gtk.Window.__init__(self)
self.set_default_size(750, 500)
self.connect("destroy", Gtk.main_quit)
self.list_view()
def list_view(self):
self.table = Gtk.Table(n_rows=3, n_columns=3, homogeneous=True)
listbox = Gtk.ListBox()
self.add(self.table)
self.add(listbox)
self.two_d_array = {'Hello' : 'Hi', 'Example' : 'Merhaba'}
for i in self.two_d_array.keys():
## label yerine buton oluşturduk
items = Gtk.Button.new_with_label(i)
items.connect("button-press-event",self.button_clicked)
listbox.add(items)
self.table.attach(listbox,0,1,0,3)
self.add(self.notebook)
self.table.attach(self.notebook,1,3,0,3)
self.notebook.show_all()
self.page1 = Gtk.Box()
self.page1.set_border_width(10)
self.page1.add(Gtk.Label(label="Merhaba bu ilk sayfa."))
self.notebook.append_page(self.page1, Gtk.Label(label="Default Page"))
def context_menu(self):
menu = Gtk.Menu()
menu_item = Gtk.MenuItem("New Page")
menu.append(menu_item)
menu_item.connect("activate", self.on_click_popup)
menu.show_all()
return menu
## Buton sağ click ise context menu açtı
def button_clicked(self,listbox_widget,event):
if event.type == Gdk.EventType.BUTTON_PRESS and event.button == 3:
menu = self.context_menu()
## Tıklanan objenin labelini print ediyor
print(listbox_widget.get_label())
self.labelmenu = listbox_widget.get_label()
menu.popup( None, None, None,None, event.button, event.get_time())
return True
def on_pop_menu(self, widget, event):
if event.button == 3:
widget.popup(None, None, None, None, event.button, event.time)
def on_click_popup(self, action):
## Yeni sayfa oluştur
self.new_page = Gtk.Box()
self.new_page.set_border_width(10)
self.new_page.add(Gtk.Label(label=self.two_d_array[self.labelmenu]))
self.notebook.append_page(self.new_page, Gtk.Label(label="New Page"))
self.close_button = Gtk.Button()
self.close_button.set_image(Gtk.Image(Gtk.STOCK_CLOSE,Gtk.IconSize))
self.close_button.connect('clicked')
self.close_button.show()
self.notebook.show_all()
window = MyWindow()
window.show_all()
Gtk.main()
Related
Background
I'm looking for a way to change the window that my video is being rendered into. This is necessary because there are some situations where the window can be destroyed, for example when my application switches into fullscreen mode.
Code
When the canvas is realized, the video source and sink are connected. Then when the prepare-window-handle message is emitted, I store a reference to the VideoOverlay element that sent it. Clicking the "switch canvas" button calls set_window_handle(new_handle) on this element, but the video continues to render in the original canvas.
import sys
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gst', '1.0')
gi.require_version('GstVideo', '1.0')
from gi.repository import Gtk, Gst, GstVideo
Gst.init(None)
if sys.platform == 'win32':
import ctypes
PyCapsule_GetPointer = ctypes.pythonapi.PyCapsule_GetPointer
PyCapsule_GetPointer.restype = ctypes.c_void_p
PyCapsule_GetPointer.argtypes = [ctypes.py_object]
gdkdll = ctypes.CDLL('libgdk-3-0.dll')
gdkdll.gdk_win32_window_get_handle.argtypes = [ctypes.c_void_p]
def get_window_handle(widget):
window = widget.get_window()
if not window.ensure_native():
raise Exception('video playback requires a native window')
window_gpointer = PyCapsule_GetPointer(window.__gpointer__, None)
handle = gdkdll.gdk_win32_window_get_handle(window_gpointer)
return handle
else:
from gi.repository import GdkX11
def get_window_handle(widget):
return widget.get_window().get_xid()
class VideoPlayer:
def __init__(self, canvas):
self._canvas = canvas
self._setup_pipeline()
def _setup_pipeline(self):
# The element with the set_window_handle function will be stored here
self._video_overlay = None
self._pipeline = Gst.ElementFactory.make('pipeline', 'pipeline')
src = Gst.ElementFactory.make('videotestsrc', 'src')
video_convert = Gst.ElementFactory.make('videoconvert', 'videoconvert')
auto_video_sink = Gst.ElementFactory.make('autovideosink', 'autovideosink')
self._pipeline.add(src)
self._pipeline.add(video_convert)
self._pipeline.add(auto_video_sink)
# The source will be linked later, once the canvas has been realized
video_convert.link(auto_video_sink)
self._video_source_pad = src.get_static_pad('src')
self._video_sink_pad = video_convert.get_static_pad('sink')
self._setup_signal_handlers()
def _setup_signal_handlers(self):
self._canvas.connect('realize', self._on_canvas_realize)
bus = self._pipeline.get_bus()
bus.enable_sync_message_emission()
bus.connect('sync-message::element', self._on_sync_element_message)
def _on_sync_element_message(self, bus, message):
if message.get_structure().get_name() == 'prepare-window-handle':
self._video_overlay = message.src
self._video_overlay.set_window_handle(self._canvas_window_handle)
def _on_canvas_realize(self, canvas):
self._canvas_window_handle = get_window_handle(canvas)
self._video_source_pad.link(self._video_sink_pad)
def start(self):
self._pipeline.set_state(Gst.State.PLAYING)
window = Gtk.Window()
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
window.add(vbox)
canvas_box = Gtk.Box()
vbox.add(canvas_box)
canvas1 = Gtk.DrawingArea()
canvas1.set_size_request(400, 400)
canvas_box.add(canvas1)
canvas2 = Gtk.DrawingArea()
canvas2.set_size_request(400, 400)
canvas_box.add(canvas2)
player = VideoPlayer(canvas1)
canvas1.connect('realize', lambda *_: player.start())
def switch_canvas(btn):
handle = get_window_handle(canvas2)
print('Setting handle:', handle)
player._video_overlay.set_window_handle(handle)
btn = Gtk.Button(label='switch canvas')
btn.connect('clicked', switch_canvas)
vbox.add(btn)
window.connect('destroy', Gtk.main_quit)
window.show_all()
Gtk.main()
Problem / Question
Calling set_window_handle() a 2nd time seems to have no effect - the video continues to render into the original window.
I've tried setting the pipeline into PAUSED, READY, and NULL state before calling set_window_handle(), but that didn't help.
I've also tried to replace the autovideosink with a new one as seen here, but that doesn't work either.
How can I change the window handle without disrupting the playback too much? Do I have to completely re-create the pipeline?
Looking at the source code, it appears that at least GL-based implementations of VideoOverlay element update the window id on expose event.
So you could try calling:
player._video_overlay.expose()
to reinitialize the GL scene after the window handle has been changed.
If that does not work, you can create a new VideoOverlay element and add it dynamically without stopping the graph.
I'm just playing with Gtk currently, but was wondering if someone has an example code of a window that has a notebook in it, and with a click of a button or event, it opens a new tab with a Gtk (for example) entry in it and is accessible from further code.
I can't find any working code like that on the web or on this website.
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Simple Notebook Example")
self.set_border_width(3)
self.box = Gtk.VBox(spacing=6)
self.add(self.box)
self._add_tab_button = Gtk.Button(label="Add Tab")
self._add_tab_button.connect("clicked", self.add_tabs)
self.box.pack_start(self._add_tab_button, False, False, 5)
self.counter = 1
self.notebook = Gtk.Notebook()
self.box.pack_start(self.notebook, True, True, 5)
# add two tabs
self.add_tabs(None)
self.add_tabs(None)
def add_tabs(self, button):
page = Gtk.Box()
page.set_border_width(10)
page.add(Gtk.Label(label="Page %s content" % self.counter))
self.notebook.append_page(
page, Gtk.Label(label="Page %s" % self.counter))
page.show_all()
self.counter += 1
win = MyWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
I've used Wnck to check whether a window has been created like this:
screen = Wnck.Screen.get_default()
screen.force_update() # recommended per Wnck documentation
window_list = screen.get_windows()
for window in window_list:
print(window.get_name())
if window.has_name():
if window.get_name() == self.xld_main_window.get_title():
window_found = True
break
assert window_found, 'The Gtk.Window named {window_name} has not been found.'\
.format(window_name=self.xld_main_window.get_title())
# clean up Wnck (saves resources, check documentation)
window = None
screen = None
However, since dialogs don't show up in the list of tasks, I can't find them that way. What is an appropriate way of checking whether they're displayed (and modal / not modal)?
The Wnck.Screen.get_windows method returns all windows including dialogs. There is no distinction as the function returns any Wnck.Window that is currently mapped. The source goes like this:
* The #WnckScreen represents a physical screen. A screen may consist of
* multiple monitors which are merged to form a large screen area. The
* #WnckScreen is at the bottom of the libwnck stack of objects: #WnckWorkspace
* objects exist a #WnckScreen and #WnckWindow objects are displayed on a
* #WnckWorkspace.
*
* The #WnckScreen corresponds to the notion of
* <classname>GdkScreen</classname> in GDK.
GList*
wnck_screen_get_windows (WnckScreen *screen)
{
g_return_val_if_fail (WNCK_IS_SCREEN (screen), NULL);
return screen->priv->mapped_windows;
}
where screen->priv points to a struct containing some lists of the windows (mapped, stacked), a pointer to the active window, etc. Some WnckWindow can have WNCK_WINDOW_DIALOG set and be a dialog.
The WnckWindow class also provides a function transient_is_most_recently_activated() to know if the focus should go to a transient child window when selected in a WnckTaskList or to minimize the transient window with its parent. For example, to know wether My Application window has a most recently activated transient:
screen = Wnck.Screen.get_default()
screen.force_update() # recommended per Wnck documentation
window_list = screen.get_windows()
for window in window_list:
if window.get_name() == 'My Application':
print(window.transient_is_most_recently_activated())
The script below catches the dialogs as other mapped windows (no matter if they are modal/non-modal or the application they are from).
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Wnck', '3.0')
from gi.repository import Gtk, Wnck
class DialogExample(Gtk.Dialog):
def __init__(self, parent):
Gtk.Dialog.__init__(self, "My Dialog", parent, 0, #or Gtk.DialogFlags.MODAL
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OK, Gtk.ResponseType.OK))
self.set_default_size(100, 100)
label = Gtk.Label("This is a dialog to display additional information")
box = self.get_content_area()
box.add(label)
self.show_all()
class DialogWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Dialog Example")
self.set_border_width(6)
button = Gtk.Button("Open dialog")
button.connect("clicked", self.on_button_clicked)
self.add(button)
def on_button_clicked(self, widget):
dialog = DialogExample(self)
response = dialog.run()
if response == Gtk.ResponseType.OK:
print("The OK button was clicked")
elif response == Gtk.ResponseType.CANCEL:
print("The Cancel button was clicked")
screen = Wnck.Screen.get_default()
screen.force_update() # recommended per Wnck documentation
window_list = screen.get_windows()
for window in window_list:
print(window.get_name())
window, window_list = (None,)*2
screen = None
dialog.destroy()
win = DialogWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
window = None
screen = None
Gtk.main()
Using Gdk instead of Wnck, you are doing the same thing at a slightly lower level.
Taking partially from this answer by Eye of Hell that says how to get the open windows, you can do this:
from gtk import gdk
name = "MyDialog"
root = gdk.get_default_root_window()
matches = []
for id in root.property_get("_NET_CLIENT_LIST"):
window = gdk.window_foreign_new(id)
if window and window.property_get("WM_NAME")[2] == name:
matches.append(window)
for match in matches:
print(match, match.get_modal_hint())
I want to show simple popup menu with right click, menu works right but menu separators are missing, I searched similar examples but they all using pygtk but I'm using gi.repository I don't know is my code wrong or this problem is all about libraries.
my code is
#!/usr/bin/python
from gi.repository import Gtk
class Win(Gtk.Window):
def __init__(self):
super(Win, self).__init__()
self.resize(400,280)
self.button = Gtk.Button()
self.add(self.button)
self.button.connect("button-press-event", self.button_press)
self.connect("destroy", Gtk.main_quit)
self.show_all()
def button_press(self,widget,event):
if event.button == 3:
self.menu = Gtk.Menu()
self.menu_copy = Gtk.MenuItem("Copy")
self.menu_paste = Gtk.MenuItem("Paste")
self.menu_select_all = Gtk.MenuItem("Select All")
self.menu.append(self.menu_copy)
self.menu.append(self.menu_paste)
# separator 1
self.menu.append(Gtk.SeparatorMenuItem())
# separator 2
self.menu.append(Gtk.MenuItem())
self.menu.append(self.menu_select_all)
self.menu.show_all()
self.menu.popup(None, None, None, None, event.button, event.get_time())
pass
def main():
app = Win()
Gtk.main()
if __name__ == "__main__":
main()
and here is the screenshot of my menu Example 1
What version of pygobject do you have? I submitted a patch for that back in June and it was fixed in 3.3.4: https://bugzilla.gnome.org/show_bug.cgi?id=670575
If the separator works properly when you use Gtk.SeparatorMenuItem.new() instead of the constructor than you know it's the aforementioned bug.
Can somebody provide a code snippet that can be used under Gtk3 to change the cursor to a hour glass using python..?
The following Window implementation does that:
import time
from gi.repository import Gdk, Gtk, GObject
class MainWindow(Gtk.Window):
"""Example window."""
def __init__(self):
"""Create new instance."""
super(MainWindow, self).__init__()
self.set_title('Test Windows')
box = Gtk.VBox()
label = Gtk.Label("Just a label....")
box.pack_start(label, True, True, 0)
button = Gtk.Button(" and a button")
box.pack_start(button, True, True, 0)
self.add(box)
self.connect("destroy", Gtk.main_quit)
self.show_all()
def set_watch(self):
"""Set the mouse to be a watch."""
watch = Gdk.Cursor(Gdk.CursorType.WATCH)
gdk_window = self.get_root_window()
gdk_window.set_cursor(watch)
def long_call(self):
"""Perform a long call."""
time.sleep(10) # your time consuming operation here
arrow = Gdk.Cursor(Gdk.CursorType.ARROW)
gdk_window = self.get_root_window()
gdk_window.set_cursor(arrow)
window = MainWindow()
window.set_watch()
GObject.idle_add(window.long_call)
Gtk.main()
It is important that you do set the pointer to be a watch OUTSIDE the idel_add call otherwise it won't be set.