Catching a click anywhere inside a gtk.Window - python

consider the following python code:
import gtk
class MainWindow():
def __init__(self):
self.window = gtk.Window()
self.window.show()
if __name__ == "__main__":
main = MainWindow()
gtk.main()
I'd need to catch clicks anywhere inside this gtk.Window().
I haven't found any suitable event (I also tried button-press-event, but it doesn't work), what am I missing?
Thank you!

You can pack a gtk.EventBox into the window. In general, whenever you have troubles catching events, check if gtk.EventBox solves them.
import gtk
class MainWindow():
def __init__(self):
self.window = gtk.Window()
self.box = gtk.EventBox ()
self.window.add (self.box)
self.box.add (gtk.Label ('some text'))
self.window.show_all()
import sys
self.box.connect ('button-press-event',
lambda widget, event:
sys.stdout.write ('%s // %s\n' % (widget, event)))
if __name__ == "__main__":
main = MainWindow()
gtk.main()
Note, however, that event propagation upwards the widget hierarchy will stop if a widget handles event itself. For instance, a parent of gtk.Button won't receive click events from it.

So i have this DrawingArea in Window. And on click i get the callback
self.drawingarea = gtk.DrawingArea()
self.drawingarea.connect ('button-press-event',self.callback)
self.drawingarea.set_events(gtk.gdk.EXPOSURE_MASK
| gtk.gdk.LEAVE_NOTIFY_MASK
| gtk.gdk.BUTTON_PRESS_MASK
| gtk.gdk.POINTER_MOTION_MASK
| gtk.gdk.POINTER_MOTION_HINT_MASK )
self.window.add(self.drawingarea)
Filter the left or right button:
def callback(self, widget, event):
print "clicking... left or right"
if event.button == 1:
print 'OK - clicked left '
#os.system("""wmctrl -s 0""")
return True

Related

How can I detect when one window occludes another in PyQt5?

I'm using PyQt5 to create an app with multiple main windows. I want to be able to allow the user to save and load window sizes and window positions. That's easy with, e.g., QMainWindow.saveGeometry() and QMainWindow.loadGeometry() or the corresponding .saveState() and .loadState() variants. These work great for position and size, but if the user moves or resizes one window so that it occludes another, I want to also restore this positioning. I don't mind writing my own code to save the info for each window, but I can't see any way to detect the relative Z order of windows. Am I missing it in the docs, or is this not possible?
To see what I mean, try this:
from PyQt5.QtWidgets import QApplication, QMainWindow, QPlainTextEdit
from PyQt5.QtCore import QSettings
from PyQt5.QtGui import QCloseEvent
'''
context: Linux Mint 19.3 Tricia x86_64
Python 3.9
PyQt5 5.15.1
'''
class RememberWin(QMainWindow):
def __init__(self, win_name: str):
super(RememberWin, self).__init__()
self.win_name = win_name
self.setWindowTitle(win_name)
self.can_close = False
def restore_window(self) -> bool:
try:
settings = QSettings("PyQtExamples", "RememberWinTest")
self.restoreGeometry(settings.value(f'{self.win_name} Geometry'))
self.restoreState(settings.value(f'{self.win_name} State'))
return True
except:
return False
def closeEvent(self, event: QCloseEvent):
if not self.can_close:
event.ignore()
else:
settings = QSettings("PyQtExamples", "RememberWinTest")
settings.setValue(f'{self.win_name} Geometry', self.saveGeometry())
settings.setValue(f'{self.win_name} State', self.saveState())
QMainWindow.closeEvent(self, event)
class ControlWindow(RememberWin):
def __init__(self, win_name: str = "ControlWindow"):
super(ControlWindow, self).__init__(win_name=win_name)
self.can_close = True
self.window1 = RememberWin(win_name='WindowOne')
self.window2 = RememberWin(win_name='WindowTwo')
self.text = QPlainTextEdit(self)
s = "Try making Window1 wide enough to cover Window2.\n" \
"Then close this window (auto closes others).\n" \
"Re-run the app and you'll notice that Window2\n" \
"is not on top of Window1 which means that this\n" \
"info isn't getting saved."
self.text.setPlainText(s)
self.setCentralWidget(self.text)
if not self.restore_window():
self.setGeometry(100, 390, 512, 100)
if not self.window1.restore_window():
self.window1.setGeometry(100, 100, 512, 384)
if not self.window2.restore_window():
self.window2.setGeometry(622, 100, 512, 384)
self.window1.show()
self.window2.show()
def closeEvent(self, event: QCloseEvent):
for win in (self.window1, self.window2):
win.can_close = True
win.close()
super(ControlWindow, self).closeEvent(event)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = ControlWindow(win_name='ControlWindow (You can only close this one)')
window.show()
sys.exit(app.exec_())
The simplest way to do what you want to achieve is to keep track of the current focused widget, or, to be precise, the top level window of the last focused widget.
You can store the focused windows in the settings as a list, using a unique objectName for each window (you are already doing this, so you just need to use setObjectName()), then restore the window by showing them in the correct order as long as the object name matches.
class RememberWin(QMainWindow):
def __init__(self, win_name: str):
super(RememberWin, self).__init__()
self.win_name = win_name
self.setObjectName(win_name)
self.setWindowTitle(win_name)
self.can_close = False
# ...
class ControlWindow(RememberWin):
def __init__(self, win_name: str = "ControlWindow"):
# ...
self.settings = QSettings("PyQtExamples", "RememberWinTest")
self.zOrder = []
QApplication.instance().focusObjectChanged.connect(self.focusChanged)
windowOrder = self.settings.value('windowOrder', type='QStringList')
topLevelWindows = QApplication.topLevelWidgets()
if windowOrder:
for objName in windowOrder:
for win in topLevelWindows:
if win.objectName() == objName:
win.show()
else:
self.window1.show()
self.window2.show()
def focusChanged(self, obj):
if not obj or obj.window() == self.window():
return
if obj.window() in self.zOrder[:-1]:
self.zOrder.remove(obj.window())
self.zOrder.append(obj.window())
def closeEvent(self, event: QCloseEvent):
for win in (self.window1, self.window2):
win.can_close = True
win.close()
self.settings.setValue('windowOrder',
[w.window().objectName() for w in self.zOrder])
super(ControlWindow, self).closeEvent(event)

Python Gtk Notebook making a new tab open from a button

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()

python gi.repository.gtk menu separators are missing

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.

PyGTK leave-notify-event shouldn't be triggered if enter children

Please see this code example:
import gtk
class MenuBox(gtk.EventBox):
def __init__(self):
super(MenuBox, self).__init__()
self.set_visible_window(False)
self.connect('enter-notify-event', self._on_mouse_enter)
self.connect('leave-notify-event', self._on_mouse_leave)
btn = gtk.Button('x')
btn.set_border_width(12)
self.add(btn)
def _on_mouse_enter(self, wid, event):
print '_on_mouse_enter'
def _on_mouse_leave(self, *args):
print '_on_mouse_leave'
def main():
win = gtk.Window()
win.connect('destroy', gtk.main_quit)
win.add(MenuBox())
win.show_all()
gtk.main()
if __name__ == '__main__':
main()
I want that the enter and leave events are not triggered if I am going from parent to child and back. I know that in this particular case I can filter these events with event.detail. But this does not work if there is no border. If I remove the border the events aren't triggered at all.
In my real code I have a more complex widget (based on gtk.Fixed) which has border at the beginning but not at the end. So just moving the event to the child wouldn't do the trick either.
# self.set_visible_window(False)
self.connect('enter-notify-event', self._on_mouse_enter)
self.connect('leave-notify-event', self._on_mouse_leave)
btn = gtk.Button('x')
# btn.set_border_width(12)
Is that what you need?

Python making gtk.Layout with Scrollbars

How could I have a scrollbar inside a gtk.Layout.
For example, in my code I have:
import pygtk
pygtk.require('2.0')
import gtk
class ScrolledWindowExample:
def __init__(self):
self.window = gtk.Dialog()
self.window.connect("destroy", self.destroy)
self.window.set_size_request(300, 300)
self.scrolled_window = gtk.ScrolledWindow()
self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.window.vbox.pack_start(self.scrolled_window, True, True, 0)
self.layout = gtk.Layout()
self.scrolled_window.add(self.layout)
self.current_pos = 0
self.add_buttom()
self.window.show_all()
def add_buttom(self, widget = None):
title = str(self.current_pos)
button = gtk.ToggleButton(title)
button.connect_object("clicked", self.add_buttom, None)
self.layout.put(button, self.current_pos, self.current_pos)
button.show()
self.current_pos += 20
def destroy(self, widget):
gtk.main_quit()
if __name__ == "__main__":
ScrolledWindowExample()
gtk.main()
What I really want is to find some way to make the scroll dynamic. See the example that I put above, when you click any button, another button will be added. But the scrollbar doesn't work.
What can I do to get the scroll bars working?
Does it works if you either use gtk.Window() instead of gtk.Dialog(); or execute self.window.run() after self.window.show_all()?
The difference between Dialog and common Window is that Dialog has its own loop which processes events. As you do not run its run() command, this loop never gets the chance to catch the events, so ScrolledWindow does not receives them, and does not change its size.

Categories

Resources