I'm using Gtk+ 3 in a Python program I'm working on and I need the "columns" in a GtkTreeView to be rendered in horizontally instead of the vertical way they are now.
As you can see from this GIF, because the attachment names stack up, it expands the TreeView upwards, not what I want.
I'm using Glade to design the GUI and I can't find any options for this, nor can I find any mention of it in the Gtk+ 3 Docs.
Is this possible, or am I going to have to figure out how to hack a solution with multiple columns?
I want it to end up looking something like this:
If you use a Gtk.FlowBox with Gtk.Labels, you can do it like this. However, there is probably a better way than packing every Gtk.Label in a Gtk.EventBox.
from gi.repository import Gtk, Gdk
import string
class Window(Gtk.Window):
def __init__(self):
super().__init__()
self.connect('delete-event', Gtk.main_quit)
self.set_size_request(200, 150)
flowbox = Gtk.FlowBox()
self.add(flowbox)
for x in string.ascii_lowercase:
eventbox = Gtk.EventBox()
eventbox.add(Gtk.Label(label=x))
flowbox.add(eventbox)
eventbox.connect('button-press-event', self.on_button_press)
def on_button_press(self, widget, event):
if event.button == 3:
print('Right click on: ' + widget.get_child().get_text())
win = Window()
win.show_all()
Gtk.main()
Related
A long time ago, I wanted to make a logo appear on top of the text in a QPushButton stacked on top of each other, but I couldn't find anyway
I read some stylesheets (couldn't find a single doc to read it all about all styles I can apply to a button)
tried the setLayoutDirection (RightToLeft and LeftToRight were there, but no UpToDown direction)
In my (I wish) last attempt I tried to inherit a QAbstractButton (I didn't find QAbstractPushButton, so I guess QAbstractButton is the answer) and change its paintEvent/paintEngine to draw an image or maybe add a vbox inside it as a layout to draw to components, but I can't find anything in python (specially PySide) which has an example in any possible way close to that. The best thing I found was the analogue clock example which was not very helpful because it was trying to work a QWidget and not a QAbstractButton and I want to keep the feel of a Native looking button.
I like my final product to be something like this.
source of the implemention of that
Python Enaml toolkit supported this feature out of the box (in one of its widgets), and I know it is QT based, so I really wish to know how it is possible?
p.s.: Also, is there a market for qt widgets? e.g.: a plugin system. Because rewriting an android like switch doesn't seem like the correct thing that I should do! even a good tutorial or doc would be appreicated (excluding official doc)
It is easier than you think, you can use QToolButton() like this:
import sys
from PySide6.QtCore import Qt, QSize
from PySide6.QtWidgets import QApplication, QVBoxLayout,QStyle, QWidget,
QToolButton
class Window(QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
button = QToolButton()
# here you choose the position of the icon and its text
button.setToolButtonStyle(
Qt.ToolButtonStyle.ToolButtonTextUnderIcon)
# here I just use built-in icon by PySide6 for this example
name = 'SP_DialogSaveButton'
pixmapi = getattr(QStyle, name)
icon = self.style().standardIcon(pixmapi)
# here we set text and icon of size 32x32 to the button
button.setIcon(icon)
button.setText("Sample text")
button.setIconSize(QSize(32, 32))
# finally we add our button to the layout
lay = QVBoxLayout(self)
lay.addWidget(button, alignment=Qt.AlignCenter)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec())
I'm using gtk.Table in combination with an EventBox for every cell to draw a colored grid. After trying out a minimal example i've discovered that the window is twice as big as the actual table. Also it's not possible to shrink the window any further when the application is running.
It seems like something went horrible wrong but i'm not able to figure out the cause. Here's the minimal example to reproduce the misbehaviour:
#!/usr/bin/env python
import pygtk
pygtk.require('2.0')
import gtk
class MyProgram:
def __init__(self):
app_window = gtk.Window(gtk.WINDOW_TOPLEVEL)
app_window.set_border_width(10)
app_window.connect("delete_event", lambda w,e: gtk.main_quit())
vbox_app = gtk.VBox(False, 0)
table_layout = gtk.Table(rows=1,columns=1, homogeneous=True)
for col in range(1,10):
for row in range(1,5):
event_box = gtk.EventBox()
label_day = gtk.Label("")
label_day.set_size_request(18,18)
label_day.show()
event_box.add(label_day)
event_box.modify_bg(gtk.STATE_NORMAL,
event_box.get_colormap().alloc_color("orange"))
event_box.set_border_width(25)
event_box.show()
table_layout.attach(event_box, 0, col, 0, row, 0,0,0,0)
vbox_app.pack_start(table_layout)
app_window.add(vbox_app)
app_window.show_all()
return
def main():
gtk.main()
return 0
if __name__ == "__main__":
MyProgram()
main()
It turns out it's your event_box.set_border_width(25) that hurts. If you just want to space evenly your labels, us the padding arguments of GtkTable::attach instead.
Here are unrelated improvements:
don't connect gtk_main_quit to the delete-event signal, connect it to the destroy signal instead. delete-event is when you want to do something before quitting (for example, display a popup "are you sure ? yes/no"), but what you want is to quit gtk when the window is really destroyed.
Also, instead of prepending your widgets when adding them in the table, append them and use a range starting from 0 so it's easier to see where the widgets are added (the indexes in the table are zero-based).
As for your VBox, in this context it's useless. If you only have widget which content takes the whole window, just add it directly to your GtkWindow (but maybe it's needed in our unstripped version of the program).
Finally, you don't need to call gtk_widget_show on each widget. Just focus on constructing your widget hierarchy, and then run gtk_widget_show_all on the toplevel window. It will recursively show all the widgets in it.
That gives us in the end:
#!/usr/bin/env python
import pygtk
pygtk.require('2.0')
import gtk
class MyProgram:
def __init__(self):
app_window = gtk.Window(gtk.WINDOW_TOPLEVEL)
app_window.set_border_width(10)
app_window.connect('destroy', lambda w: gtk.main_quit())
table = gtk.Table(rows=1, columns=1, homogeneous=True)
for col in range(0,9):
for row in range(0,4):
event_box = gtk.EventBox()
label_day = gtk.Label('')
label_day.set_size_request(18, 18)
event_box.add(label_day)
event_box.modify_bg(gtk.STATE_NORMAL,
event_box.get_colormap().alloc_color("orange"))
# event_box.set_border_width(25)
table.attach(event_box, col, col + 1, row, row + 1, 0, 0, 12, 12)
app_window.add(table)
app_window.show_all()
if __name__ == '__main__':
MyProgram()
gtk.main()
You also have a tool named gtk-inspector but I don't know if it works with GTK 2. If not, fallback on gtk-parasite. These tools will help you analyze a running gtk user interface and see the characteristics of its widgets.
Also, GTK 3 has been out for a few years now and GTK 4 is on the road. Consider using GTK 3 for new code. It doesn't use pygtk anymore, it's pygobject instead trough the gi package (GObject introspection).
Here's the GTK 3 in python official tutorial:
https://python-gtk-3-tutorial.readthedocs.io/en/latest/index.html
Basically what i need to achieve with this is to bypass the bug which doesn't identify the mouse over the top bar as being inside the window. As you can see with the code below, if you put the mouse on top bar the window turns half-transparent as if the mouse aren't there (mouse_enter() doesn't get called).
Well, so i thought the only way to do this is to get mouse coordenates/position and work from there in the mouse_move() function, the problem now is that motion-notify-event doesn't get fired.
import gtk
def mouse_move(window, event):
print(win.get_pointer())
win.set_opacity(1)
def mouse_enter(window, event):
win.set_opacity(1)
def mouse_leave(window, event):
win.set_opacity(0.5)
win = gtk.Window()
win.set_opacity(0.5)
win.set_size_request(600, 400)
win.connect('enter-notify-event', mouse_enter)
win.connect('leave-notify-event', mouse_leave)
win.connect('motion-notify-event', mouse_move)
win.connect('destroy', gtk.main_quit)
win.show_all()
gtk.main()
You likely need to call win.add_events() with the Python equivalent of GDK_POINTER_MOTION_MASK.
I need to find a way to load a image from file such that the image is actual size. I have read documentation [here][https://lazka.github.io/pgi-docs/Gtk-3.0] and [here][http://python-gtk-3-tutorial.readthedocs.org/en/latest/index.html] but the only way that seems to work is using the builder class to load a gui designed in glade. However via code I came up with the following and this does not produce the desired result, image is clipped.
from gi.repository import Gtk
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title='GMouse 600')
self.layout = Gtk.Layout.new(None,None)
self.add(self.layout)
self.background = Gtk.Image.new_from_file('./images/g600-thumb-buttons.jpg')
self.layout.put(self.background, 0, 0)
window = MainWindow()
window.connect('delete-event', Gtk.main_quit)
window.show_all()
Gtk.main()
I’m trying to find out how I can do this via code, in such a way that my image is filling the window. Can someone please provide any suggestions or possible solutions that I can try.
Note that the reason I wish to do this via code is when I use glade it does produce the desired result except when I try to add a grid layout on top of the image, or any other widget, it will not allow me. Also coding it will give me a chance to better learn and my gui is rather small, very few widgets will be used.
It seems I have solved the problem with the following code using Gtk.Overlay
from gi.repository import Gtk
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title='GMouse 600')
self.overlay = Gtk.Overlay()
self.add(self.overlay)
self.background = Gtk.Image.new_from_file('./images/g600-thumb-buttons.jpg')
self.overlay.add(self.background)
self.grid = Gtk.Grid()
self.button = Gtk.Button(label='Test')
self.grid.add(self.button)
self.overlay.add_overlay(self.grid)
window = MainWindow()
window.connect('delete-event', Gtk.main_quit)
window.show_all()
Gtk.main()
I'm looking for very long time for a solution for this. I want to delete the Titlebar of a Tk window, like with the function "overridedirect()". My problem with that function is, that there is no icon on the taskbar of the OS.
I also tried it with "root.attributes("-fullscreen", 1)" and tried to scale it down, but that doesn't work either.
I hope somebody knows a good solution, thanks for help!
My code looks kind of like this now:
from tkinter import *
class Main(Frame):
def __init__(self, root):
**...**
#There are more classes after this one, but defined the same way
def main():
root = Tk()
root.geometry("800x400+0+0")
root.minsize(700, 400)
root.title("Title")
#root.overrideredirect(True)
#root.iconify()
##root.attributes('-topmost', 1)
##root.attributes("-fullscreen", 1)
##root.wm_state("zoomed")
if __name__ == "__main__":
main()
You cannot do what you want. You can either have no titlebar and no icon, or you can have a titlebar and icon. There is no way to get one without the other.