Putting other widgets in gtk.Menu - python

I'd like to be able to put a gtk.ProgressBar in my gtk.Menu, but since menus only takes gtk.MenuItems and its subclasses, what I've done instead is take a plain gtk.MenuItem and tried adding my progress bar as a child to that. Since gtk.MenuItem is a subclass of gtk.Bin, it should be able to hold pretty much any widget.
Example:
menu = gtk.Menu()
item = gtk.MenuItem()
button = gtk.ProgressBar()
button.pulse()
button.show()
item.add(button)
item.show()
menu.append(item)
This runs just fine without pygtk complaining at all. However, my progress bar is simply not shown:
If I replace the progressbar with a gtk.Label, it's shown just fine.
Now to my questions:
How do I know which widgets it will take?
How do I trick it into letting me put other widgets in there?

This is a limitation of Ubuntu's Application Indicators, see this question at askubuntu.

Your example code works here(I tested it by modifying a pygtk example that I will paste below).
Maybe its an issue with the rest of your code or your theme?
#!/usr/bin/env python
# example menu.py
import pygtk
pygtk.require('2.0')
import gtk
class MenuExample:
def __init__(self):
# create a new window
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.set_size_request(200, 100)
window.set_title("GTK Menu Test")
window.connect("delete_event", lambda w,e: gtk.main_quit())
# Init the menu-widget, and remember -- never
# show() the menu widget!!
# This is the menu that holds the menu items, the one that
# will pop up when you click on the "Root Menu" in the app
menu = gtk.Menu()
### MODIFIED PART!! ###
item = gtk.MenuItem()
button = gtk.ProgressBar()
button.pulse()
button.show()
item.add(button)
item.show()
menu.append(item)
#### END MODIFIED PART ####
# This is the root menu, and will be the label
# displayed on the menu bar. There won't be a signal handler attached,
# as it only pops up the rest of the menu when pressed.
root_menu = gtk.MenuItem("Root Menu")
root_menu.show()
# Now we specify that we want our newly created "menu" to be the
# menu for the "root menu"
root_menu.set_submenu(menu)
# A vbox to put a menu and a button in:
vbox = gtk.VBox(False, 0)
window.add(vbox)
vbox.show()
# Create a menu-bar to hold the menus and add it to our main window
menu_bar = gtk.MenuBar()
vbox.pack_start(menu_bar, False, False, 2)
menu_bar.show()
# Create a button to which to attach menu as a popup
button = gtk.Button("press me")
button.connect_object("event", self.button_press, menu)
vbox.pack_end(button, True, True, 2)
button.show()
# And finally we append the menu-item to the menu-bar -- this is the
# "root" menu-item I have been raving about =)
menu_bar.append (root_menu)
# always display the window as the last step so it all splashes on
# the screen at once.
window.show()
# Respond to a button-press by posting a menu passed in as widget.
#
# Note that the "widget" argument is the menu being posted, NOT
# the button that was pressed.
def button_press(self, widget, event):
if event.type == gtk.gdk.BUTTON_PRESS:
widget.popup(None, None, None, event.button, event.time)
# Tell calling code that we have handled this event the buck
# stops here.
return True
# Tell calling code that we have not handled this event pass it on.
return False
# Print a string when a menu item is selected
def menuitem_response(self, widget, string):
print "%s" % string
def main():
gtk.main()
return 0
if __name__ == "__main__":
MenuExample()
main()

Related

The secondary window is automatically hidden after after clicking the "OK" button of the Messagebox. Are you doing to hide it?

Working in a secondary window with Tkinter, when I click on the "OK" button of the Messagebox message (Record insert correctly), this secondary window disappears and is hidden at the bottom of the taskbar. So immediately click "OK" in the Messagebox, I'll find myself automatically on the main window. I don't get errors
How can I not hide the secondary window in the taskbar and then stay inside the secondary when I click the "OK" button of the Messagebox? What should I write in the "Insert?"
Code Windows Main:
window=Tk()
window.title("main")
window.attributes('-zoomed', True)
Code Windows Secondary
from aaa import bbb
def form_secondary():
root = tk.Toplevel()
root.title("secondary")
root.geometry("1920x1080+0+0")
root.config(bg="white")
root.state("normal")
Function that launches MessageBox
def insert():
if aaaa() == "" or bbbb.get() =="" or cccc.get() == "" or ddddd.get() == "" or eeee.get() == "" or fffff.get() == "":
messagebox.showerror("There is some empty field. Fill out all the fields")
return
db.insert(aaaa.get(), bbbb.get(), cccc.get(), ddddd.get(), eeee.get, fffff.get())
messagebox.showinfo("Record insert correctly ")
clearAll()
dispalyAll()
You can keep a child window on top of its parent window by making the child window a transient window of parent window.
Since creation of window (in main script) and root (inside form_secondary() in another script) windows are in different scripts, you cannot refer window inside form_secondary() directly. One of the way is to pass window to form_secondary() as an argument:
def form_secondary(parent):
root = tk.Toplevel(parent)
root.title("secondary")
root.geometry("1920x1080+0+0")
root.config(bg="white")
root.state("normal")
# make this window a transient window
root.transient(parent)
And then pass window as an argument when calling form_secondary() in main script:
...
window=Tk()
window.title("main")
window.attributes('-zoomed', True)
...
# assume it is called inside a function
def some_func():
...
form_secondary(window)
...
...
Update: if it is called via a menu item, then use lambda.
For example:
editmenu.add_command(label='Database', command=lambda: name.form_secondary(window))

Using a dialog/window app with a SysTray icon: focus problem

I want to use a dialog together with the SysTrayIcon.
The reason for the app is running in a systray, and show the dialog when you press the icon button. The app will close entirely just from the menu option.
Problem to solve: when lose focus (eg:clicking outisde) he dialog should hide even if the dialog had a button to display a modal window
Please test the sample code, as it illustrates everything.
from PySide2.QtWidgets import *
import sys
message = '''
This is a dialog we wanna use together with the SysTrayIcon
The reason of the app is running in a systray, and show the
dialog when you press the icon button. The app will close
entirely from the menu option, explained below.
Clicking SysTray icon use:
1) Click left and right in icon it shows the app
and you can interact with it. If you click again it toggles
show/hide the app.
2) With Middle Click a menu shows up, and dialog hides.
From this menu you can close the app entirely.
PROBLEM TO SOLVE:
When lose focus(eg:clicking outisde) he dialog should hide
Even if the dialog had a button to display a modal window
'''
class LauncherDialog(QDialog):
def __init__(self, x=None, y=None, parent=None):
super(LauncherDialog, self).__init__(parent)
my_lbl = QLabel(message)
my_layout = QVBoxLayout()
my_layout.addWidget(my_lbl)
my_layout.setMargin(0)
self.setLayout(my_layout)
self.setMinimumHeight(630)
self.setMinimumWidth(360)
self.setWindowTitle("Launcher")
if x is not None and y is not None:
self.move(x, y)
class SystrayLauncher(object):
def __init__(self):
# Create the icon
w = QWidget() #just to get the style(), haven't seen other way
icon = w.style().standardIcon(QStyle.SP_MessageBoxInformation)
# Create the tray
self.tray = QSystemTrayIcon()
self.tray.setIcon(icon)
self.tray.setVisible(True)
self.tray_pos = self.tray.geometry()
left = self.tray_pos.left()
height = self.tray_pos.height()
self.menu = QMenu()
self.action = QAction("&Quit", None, triggered=QApplication.instance().quit)
self.tray.setContextMenu(self.menu)
self.launcher_window = LauncherDialog(x=left, y=height)
self.tray.activated.connect(self.handleLeftRightMiddleClick)
def handleLeftRightMiddleClick(self, signal):
if signal == QSystemTrayIcon.ActivationReason.MiddleClick:
self.menu.addAction(self.action) #show menu
self.launcher_window.hide()
elif signal == QSystemTrayIcon.ActivationReason.Trigger: #left / right clicks
self.menu.removeAction(self.action) #hide menu
if self.launcher_window.isHidden():
self.launcher_window.show()
else:
self.launcher_window.hide()
else: #doubleclick
pass
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setQuitOnLastWindowClosed(False)
sl = SystrayLauncher()
sys.exit(app.exec_())

Qt menu artifact when calling input dialog

I am building a PyQt application which is supposed to receive mouse right-click drags on a QGraphicsView, draw a "lasso" (a line stretching from the drag origin to the mouse position, and a circle at the mouse position), and then, on mouse release, erase the lasso graphics and display an input dialog for the next part of the app.
For some reason, when I use the mouse to click "Ok" on the input dialog, a menu artifact appears on the QGraphicsView which contained the lasso. The menu artifact is a drop-down menu line that says "(check mark) Exit". Occasionally it may be the context menu for one of my custom QGraphicsObjects as well - but for whatever reason, calling the dialog and then clicking "Ok" results in an unintended right-click-like event on the QGraphicsView.
This only seems to happen when the last step before method return is the QInputDialog - replacing it with a pass or a call to some other method does not result in the artifact. I'd be very grateful to anyone with a clue to what is causing this problem!
Here's the minimal code:
import sys
from PyQt4 import QtCore, QtGui
class Window(QtGui.QMainWindow):
# The app main window.
def __init__(self):
super(Window, self).__init__()
# Initialize window UI
self.initUI()
def initUI(self, labelText=None):
# Set user-interface attributes.
# Set up menu-, tool-, status-bars and add associated actions.
self.toolbar = self.addToolBar('Exit')
# Create a menu item to exit the app.
exitAction = QtGui.QAction(QtGui.QIcon('icons/exit.png'), '&Exit', self)
exitAction.triggered.connect(QtGui.qApp.quit)
self.toolbar.addAction(exitAction)
# Create the main view.
self.viewNetwork = NetworkPortal()
self.viewNetwork.setMinimumWidth(800)
self.viewNetwork.setMinimumHeight(800)
self.setCentralWidget(self.viewNetwork)
self.show()
class NetworkPortal(QtGui.QGraphicsView):
# A view which allows you to see and manipulate a network of nodes.
def __init__(self):
super(NetworkPortal, self).__init__(QtGui.QGraphicsScene())
# Add the CircleThing graphic to the scene.
circleThing = CircleThing()
self.scene().addItem(circleThing)
class CircleThing(QtGui.QGraphicsEllipseItem):
# Defines the graphical object.
def __init__(self):
super(CircleThing, self).__init__(-10, -10, 20, 20)
# Set flags for the graphical object.
self.setFlags(
QtGui.QGraphicsItem.ItemIsSelectable |
QtGui.QGraphicsItem.ItemIsMovable |
QtGui.QGraphicsItem.ItemSendsScenePositionChanges
)
self.dragLine = None
self.dragCircle = None
def mouseMoveEvent(self, event):
# Reimplements mouseMoveEvent to drag out a line which can, on
# mouseReleaseEvent, form a new Relationship or create a new Thing.
# If just beginning a drag,
if self.dragLine == None:
# Create a new lasso line.
self.startPosX = event.scenePos().x()
self.startPosY = event.scenePos().y()
self.dragLine = self.scene().addLine(
self.startPosX,
self.startPosY,
event.scenePos().x(),
event.scenePos().y(),
QtGui.QPen(QtCore.Qt.black, 1, QtCore.Qt.SolidLine)
)
# Create a new lasso circle at the location of the drag position.
self.dragCircle = QtGui.QGraphicsEllipseItem(-5, -5, 10, 10)
self.dragCircle.setPos(event.scenePos().x(),
event.scenePos().y())
self.scene().addItem(self.dragCircle)
# If a drag is already in progress,
else:
# Move the lasso line and circle to the drag position.
self.dragLine.setLine(QtCore.QLineF(self.startPosX,
self.startPosY,
event.scenePos().x(),
event.scenePos().y()))
self.dragCircle.setPos(event.scenePos().x(),
event.scenePos().y())
def mouseReleaseEvent(self, event):
# If the line already exists,
if self.dragLine != None:
# If the released button was the right mouse button,
if event.button() == QtCore.Qt.RightButton:
# Clean up the link-drag graphics.
self.scene().removeItem(self.dragLine)
self.dragLine = None
self.scene().removeItem(self.dragCircle)
self.dragCircle = None
# Create the related Thing.
# Display input box querying for name value.
entry, ok = QtGui.QInputDialog.getText(None, 'Enter some info: ',
'Input:', QtGui.QLineEdit.Normal, '')
return
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
newWindow = Window()
sys.exit(app.exec_())
This is a guess on my part, but I've seen this kind of weird thing before.
Some Qt widgets have default behavior on certain types of events. I've never used QGraphicsView, but often the default for a right click is to open a context-sensitive pop-up menu (usually useless, in my experience). That may be happening in your case, which would explain why you only see this when there's a right click.
You can suppress the default Qt behavior by calling event.ignore() before returning from mouseReleaseEvent.
There was not a direct answer to the cause of this bug, but using a QTimer.singleShot() to call the dialog (in combination with a QSignalMapper in order to enter parameters) is a functional workaround that separates the dialog from the method in which the bug was occurring. Thanks to #Avaris for this one.

PyGtk3, ToggleButton, "toggled-or-untoggled" event

i know "toggled-or-untoggled" event is not exist but i need to use event like this. is there a event to do task when button is "toggled" and "untoggled". i don't want use "clicked" event because ToggleButton can be toggled or untoggled without clicked
Thanks
example
def foo(obj):
if obj.get_active():
print("toggled")
else:
print("untoggled")
mybtn = gtk.ToggleButton()
mybtn.connect("toggled-or-untoggled", foo)
According to the docs -
When the state of the button is changed, the “toggled” signal is
emitted.
So, ideally, mybtn.connect("toggled", foo) should work.
Here's a short GTK2+ / PyGTK demo; it should be easy enough to adapt to GTK3, if necessary.
The GUI contains a ToggleButton and a plain Button. The ToggleButton's callback just prints the state of the button whenever it's toggled, either by the user clicking on it or by other code calling its set_active method. The plain Button prints a message when it's clicked, and it also toggles the ToggleButton.
#!/usr/bin/env python2
from __future__ import print_function
import pygtk
pygtk.require('2.0')
import gtk
class Test(object):
def __init__(self):
win = gtk.Window(gtk.WINDOW_TOPLEVEL)
win.connect("destroy", lambda w: gtk.main_quit())
box = gtk.HBox()
box.show()
win.add(box)
self.togglebutton = button = gtk.ToggleButton('toggle')
button.connect("toggled", self.togglebutton_cb)
box.pack_start(button, expand=True, fill=False)
button.show()
button = gtk.Button('plain')
button.connect("clicked", self.button_cb)
box.pack_start(button, expand=True, fill=True)
button.show()
win.show()
gtk.main()
def button_cb(self, widget):
s = "%s button pressed" % widget.get_label()
print(s)
print('Toggling...')
tb = self.togglebutton
state = tb.get_active()
tb.set_active(not state)
def togglebutton_cb(self, widget):
state = widget.get_active()
s = "%s button toggled to %s" % (widget.get_label(), ("off", "on")[state])
print(s)
Test()
typical output
toggle button toggled to on
toggle button toggled to off
plain button pressed
Toggling...
toggle button toggled to on
plain button pressed
Toggling...
toggle button toggled to off
plain button pressed
Toggling...
toggle button toggled to on
toggle button toggled to off

How to override default right-click menu in Gtk FileChooserWidget

The gtk FileChooserWidget shows a context menu on right-click with "add to bookmarks", "show hidden files", and "show size column" options. I would like to override this menu with a custom menu.
Creating a menu on right-click from other gtk widgets (window, eventbox) is easy and there are a lot of tutorials out there showing how to do it.
I can't seem to get events from a gtk filechooser widget, however. The "on_button_press_event" callback in the following code never gets called:
#!/usr/bin/env python
import gtk
class file_chooser_test():
def __init__(self):
window = gtk.Window()
window.connect("delete_event", lambda w,e: gtk.main_quit())
chooser = gtk.FileChooserWidget()
chooser.set_size_request(600, 400)
chooser.add_events(gtk.gdk.BUTTON_PRESS_MASK)
chooser.connect("button-press-event", self.on_button_press_event)
window.add(chooser)
window.show_all()
gtk.main()
def on_button_press_event(self, widget, event=None):
print "event is: ", event
if __name__ == "__main__":
test = file_chooser_test()
Can anyone shed any light on how to override the default right-click menu on the GTK FileChooserWidget?
Thanks!

Categories

Resources