PyGTK resize image - python

I would like to resize (not automatically) an image, I used .set_size_request but it made no changes.
from gi.repository import Gtk
window = Gtk.Window()
window.set_size_request(320, 240)
window.connect('delete-event', Gtk.main_quit)
box = Gtk.Box(spacing=6)
image = Gtk.Image()
image.set_from_file("C:\\Users\\alimacher\\FF0000.png")
image.set_size_request(400, 400)
box.pack_start(image, False, False, 1)
window.add(box)
window.show_all()
Gtk.main()
And please there is a way to do it without PixBuf ?
Thank you.

Related

How to fix GTK Scrolled Window not updating scroll bars after contents have changed?

I wish to have an image in my GTK app that continually resizes to fit its parent container.
I've accomplished this by getting the parent container's size inside a size-allocate event callback, and resizing my image according to those dimensions. This works fine when I'm making the window smaller, but when I want to make it bigger, it refuses to resize because it has to be at least as big as the contents (the image).
To overcome that aspect, I've placed the image in a ScrolledWindow so that I can freely resize my window smaller.
The issue lies in that when I switch the image shown to one with different dimensions, the ScrolledWindow doesn't seem to realize it, and I'm left with a ScrolledWindow with the wrong content size and unnecessary scroll bars. But alas, I can hover over the scroll bar and it realizes that it's too big for its content and removes the scroll bars. See the below demonstration.
Can I somehow have this "correction" behavior happen right away instead of when I hover over the scroll bars?
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
from gi.repository import GdkPixbuf
class Minimal(Gtk.Window):
imageShown = 0
img = Gtk.Image.new()
pixbufRed = GdkPixbuf.Pixbuf.new_from_file("kirby_red.png")
pixbufBlue = GdkPixbuf.Pixbuf.new_from_file("kirby_blue.png")
pixbuf = None
def __init__(self):
Gtk.Window.__init__(self)
self.set_default_size(400,300)
button = Gtk.Button.new_with_label("Swap Image")
button.connect("clicked", self.on_button_click)
self.pixbuf = self.pixbufRed
self.img.set_from_pixbuf(self.pixbuf)
scrolled = Gtk.ScrolledWindow()
scrolled.connect("size-allocate", self.on_size_allocated);
scrolled.add(self.img)
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,spacing=0)
box.pack_start(button, False, False, 0)
box.pack_end(scrolled, True, True, 0)
self.add(box)
#swap image shown using imageShown flag to keep track
def on_button_click(self, button):
if(self.imageShown == 0):
self.pixbuf = self.pixbufBlue
self.imageShown = 1
else:
self.pixbuf = self.pixbufRed
self.imageShown = 0
self.img.set_from_pixbuf(self.pixbuf)
def on_size_allocated(self, widget, allocation):
scaledPixbuf = Minimal.scale_image_from_allocation_keep_aspect(self.pixbuf, allocation)
self.img.set_from_pixbuf(scaledPixbuf)
#staticmethod
def scale_image_from_allocation_keep_aspect(pixbuf, allocation):
imgWidth = pixbuf.get_width()
imgHeight = pixbuf.get_height()
parentWidth = allocation.width
parentHeight = allocation.height
aspectWidth = parentWidth/imgWidth
aspectHeight= parentHeight/imgHeight
aspect=0
if(aspectWidth < aspectHeight):
aspect = aspectWidth
else:
aspect = aspectHeight
newWidth = imgWidth*aspect
newHeight = imgHeight*aspect
return pixbuf.scale_simple(newWidth, newHeight, GdkPixbuf.InterpType.BILINEAR)
win = Minimal()
win.show_all()
Gtk.main()
size-allocate isn't really the right place to be changing the contents of your widget (like changing the image widget's pixbuf), and it usually doesn't work correctly if you try to use it like that. It's intended more for custom container widgets to layout their children once the size is already determined.
In GTK 3, I usually solve the problem of making images fill the available space by creating a very simple custom widget, like this:
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GdkPixbuf, Gdk
class ScaleImage(Gtk.DrawingArea):
def __init__(self, pixbuf):
Gtk.DrawingArea.__init__(self)
self.pixbuf = pixbuf
def do_draw(self, cr):
alloc, baseline = self.get_allocated_size()
factor = min(alloc.width / self.pixbuf.get_width(), alloc.height / self.pixbuf.get_height())
cr.scale(factor, factor)
Gdk.cairo_set_source_pixbuf(cr, self.pixbuf, 0, 0)
cr.paint()
win = Gtk.Window()
img = ScaleImage(GdkPixbuf.Pixbuf.new_from_file("file.png"))
win.add(img)
win.show_all()
Gtk.main()
I haven't tried it yet, but in GTK 4 you should be able to use Gtk.Picture to get the same effect without a custom widget.

GtkOverlay hides GtkTextView

I'm trying to develop an application using Gtk, and I have run into a problem using GtkOverlay. If I have a GtkOverlay with a GtkTextView that was added using the standard container add method, the text is hidden. However, all other widgets, say for example, buttons, appear just fine. Even more odd is the fact that this behavior is only present if at least one widget was adding using add_overlay.
#!/usr/bin/env python
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
USE_OVERLAY = False
win = Gtk.Window()
text_view = Gtk.TextView()
overlay = Gtk.Overlay()
top_button = Gtk.Button()
bottom_button = Gtk.Button()
top_container = Gtk.VBox()
bottom_container = Gtk.VBox()
overlay_str = "( USE_OVERLAY = " + str(USE_OVERLAY) + ")"
win.set_title(overlay_str)
top_button.set_label("I'm a button on top!")
bottom_button.set_label("I'm a button on bottom!")
text_view.get_buffer().set_text("This should be visible")
win.add(overlay)
overlay.add(bottom_container)
bottom_container.pack_start(bottom_button, False, False, 0)
bottom_container.pack_end(text_view, True, True, 0)
if USE_OVERLAY:
overlay.add_overlay(top_container)
top_container.pack_end(top_button, False, False, 0)
win.connect("delete-event", Gtk.main_quit)
overlay.show_all()
win.show_all()
Gtk.main()
I have reason to believe that this is not a python problem, as the actual application is written using haskell-gi, however I figured more people would be familiar with python.
I don't know on what system your a running this example but it is working fine for me. The only caveat is that the top button appears over the bottom button and the TextView widget so I have to manually resize the Window to see the text. You can see a screen cast of my situation in this video: https://youtu.be/xoAH4OuEM0E
Now depending on what you really want there may be few different answers. What I would suggest is putting the TextView inside a ScrolledWindow. This way the TextView will be at least visible before you would need the resize the window. It would also have the consequence to provide scrollbars if the text overflow the visible area.
It could look like this:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
USE_OVERLAY = True
win = Gtk.Window()
text_view = Gtk.TextView()
overlay = Gtk.Overlay()
top_button = Gtk.Button()
bottom_button = Gtk.Button()
top_container = Gtk.VBox()
bottom_container = Gtk.VBox()
overlay_str = "( USE_OVERLAY = " + str(USE_OVERLAY) + ")"
win.set_title(overlay_str)
top_button.set_label("I'm a button on top!")
bottom_button.set_label("I'm a button on bottom!")
text_view.get_buffer().set_text("This should be visible")
# This is where the text_view is inserted in a ScrolledWindow
scrolled_window = Gtk.ScrolledWindow()
scrolled_window.add(text_view)
win.add(overlay)
overlay.add(bottom_container)
bottom_container.pack_start(bottom_button, False, False, 0)
# The scrolled_window is inserted in the bottom_container
bottom_container.pack_end(scrolled_window, True, True, 0)
if USE_OVERLAY:
overlay.add_overlay(top_container)
top_container.pack_end(top_button, False, False, 0)
win.connect("delete-event", Gtk.main_quit)
overlay.show_all()
win.show_all()
Gtk.main()
You can also see the result on the aforementioned screencast. The only drawback is that the top button won't be able to overlay as much the bottom layer as in your script. But maybe it won't bother you.

Transparent background of gtk.DrawingArea in python

I got a problem to set the transparent background of drawing area.
The reason what I want this is that I have a main window where is background
def draw_pixbuf(self,widget, event):
path = 'test.jpg'
pixbuf = gtk.gdk.pixbuf_new_from_file(path)
scaled_buf = pixbuf.scale_simple(800,480,gtk.gdk.INTERP_BILINEAR)
widget.window.draw_pixbuf(widget.style.bg_gc[gtk.STATE_NORMAL], scaled_buf, 0, 0, 0,0)
self.window = gtk.Window()
self.window.connect("delete-event", gtk.main_quit)
self.window.set_decorated(False)
self.window.set_position(gtk.WIN_POS_CENTER_ALWAYS)
self.window.set_size_request(800,480)
hbbox = gtk.HBox()
hbbox.connect('expose-event', self.draw_pixbuf)
so my HBox has this background and I have two Fixed containers in it - one button and one drawing area.
fix = gtk.Fixed()
image = gtk.Image()
image.set_from_file("close.png")
event_box = gtk.EventBox()
event_box.add(image)
event_box.set_size_request(30,30)
event_box.set_visible_window(False)
event_box.connect("button_press_event",gtk.mainquit)
fix.put(event_box,140,0)
self.darea = gtk.DrawingArea()
self.darea.set_size_request(450,300)
self.darea.connect("expose-event", self.expose)
fix2 = gtk.Fixed()
fix2.put(self.darea,175,90)
hbbox.pack_start(fix2, True, False, 10)
hbbox.pack_end(fix, True, False, 10)
#hbbox.pack_start(self.darea,True,False,10)
self.window.add(hbbox)
self.window.show_all()
But the drawing area overrides that HBox's background with its own default background(grey). I am able to change background by modify_bg function, but I want it transparent to write the cairo animated text on the HBox's background.
So the goal is to have background image of the window and draw the caito animated text onto it and not to grey rectangle (drawing area's background).
I am new to GTK so maybe I miss something important how to do it.
I hope you can help. Thank you.
I also have not found solution and swiched to Cairo (Pycairo)
See more there: GTK drawable area transparent background color

Gtk3 and Python - Box doesn't resize to fill window

I'm writing an app using Gtk3 and Python. I have a revealer as a sidebar to select the content and a webkit webview to display the main content. When the revealer is hidden the webview doesn't fill the entire window space and I don't know why. Any help would be appreciated.
from gi.repository import Gtk, Gio
from gi.repository import WebKit
HEIGHT = 500
WIDTH = 800
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Resolution")
self.set_border_width(0)
self.set_default_size(WIDTH, HEIGHT)
hb = Gtk.HeaderBar()
hb.props.show_close_button = True
hb.props.title = "Resolution"
self.set_titlebar(hb)
button = Gtk.Button()
icon = Gio.ThemedIcon(name="emblem-system-symbolic")
image = Gtk.Image.new_from_gicon(icon, 1)
button.add(image)
button.connect("clicked", self.sidebarShowHide)
button.set_focus_on_click(False)
hb.pack_start(button)
sidebarbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
toplevelbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
self.add(toplevelbox)
self.sidebar = Gtk.Revealer()
self.sidebar.set_transition_duration(0)
self.sidebar.set_reveal_child(False)
toplevelbox.pack_start(self.sidebar, False, False, 0)
self.sidebar.add(sidebarbox)
self.searchentry = Gtk.SearchEntry()
self.searchentry.connect("search-changed", self.search_changed)
sidebarbox.pack_start(self.searchentry, False, False, 0)
label = Gtk.Label("Contents Selector")
sidebarbox.pack_start(label, True, True, 0)
scroller = Gtk.ScrolledWindow()
content = WebKit.WebView()
scroller.add(content)
toplevelbox.pack_start(scroller, True, True, 0)
content.open("/home/oliver/resolution/placeholder.html")
def sidebarShowHide(self, button):
if self.sidebar.get_reveal_child():
self.sidebar.set_reveal_child(False)
else:
self.sidebar.set_reveal_child(True)
def search_changed(self, searchentry):
pass
win = MainWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
Well, i have done some GtkRevealer few months ago and it works. It drive me nuts to see this piece of code was not.
I opened my project again and look inside where that part is, and it turn out the toplevel container where the Gtk.Revealer resides, has to has Gtk.Orientation.VERTICAL.. if you change your "toplevelbox" orientation to that, it will work, but it wont be sidebar. It will coming from top or bottom. It goes the same if you change GtkBox with GtkGrid. If I were to guess it depends on the children default orientation.
Workaround on that, is to use widget hide/show mechanism (believe me, i ransack your code and it works).
from gi.repository import Gtk, Gio
from gi.repository import WebKit
HEIGHT = 500
WIDTH = 800
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Resolution")
self.set_border_width(0)
self.set_default_size(WIDTH, HEIGHT)
hb = Gtk.HeaderBar()
hb.props.show_close_button = True
hb.props.title = "Resolution"
self.set_titlebar(hb)
button = Gtk.Button()
icon = Gio.ThemedIcon(name="emblem-system-symbolic")
image = Gtk.Image.new_from_gicon(icon, 1)
button.add(image)
button.connect("clicked", self.sidebarShowHide)
button.set_focus_on_click(False)
hb.pack_start(button)
sidebarbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
toplevelbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
self.add(toplevelbox)
self.sidebar = Gtk.Box()
toplevelbox.pack_start(self.sidebar, False, False, 0)
self.sidebar.add(sidebarbox)
self.searchentry = Gtk.SearchEntry()
self.searchentry.connect("search-changed", self.search_changed)
sidebarbox.pack_start(self.searchentry, False, False, 0)
label = Gtk.Label("Contents Selector")
sidebarbox.pack_start(label, True, True, 0)
scroller = Gtk.ScrolledWindow()
content = WebKit.WebView()
scroller.add(content)
toplevelbox.pack_start(scroller, True, True, 0)
content.open("/home/oliver/resolution/placeholder.html")
def sidebarShowHide(self, button):
if self.sidebar.get_visible():
self.sidebar.hide ()
else:
self.sidebar.show ()
def search_changed(self, searchentry):
pass
win = MainWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
This smells like a bug.
As a workaround, you could use
def sidebarShowHide(self, button):
self.sidebarbox.set_visible(not self.sidebarbox.get_visible())
but this does not yield any transition animation, but does remove its allocated space for the time being invisible.
Actually the C demo provided within the git repo resizes as expected, so this might in fact have to do something with the child widgets prefered orientation.

Gnomeapplet - Seeing only a white dot where an entry and a button should be

I have written a gnomeapplet for gnome-panel, and the corresponding server file. Everything seems to work fine when I use the "debug mode", but when I try to load the applet from the panel it shows only a little white dot.
Can anyone help me find the problem?
my code is:
#!/usr/bin/env python
import gnomeapplet
import gobject
import sys
import gtk
class Priberam(gnomeapplet.Applet):
def __init__(self, applet, iid):
hbox = gtk.HBox(False, 0)
image = gtk.Image()
pixbuf = gtk.gdk.pixbuf_new_from_file('1.png')
pixbuf = gtk.gdk.Pixbuf.add_alpha(pixbuf,255,255,255 ,255)
size = applet.get_size()-6
pixbuf = pixbuf.scale_simple(size,size,gtk.gdk.INTERP_BILINEAR)
image.set_from_pixbuf(pixbuf)
button_search = gtk.Button()
button_search.add(image)
entry = gtk.Entry()
hbox.pack_start(button_search, False, False, 0)
hbox.pack_end(entry, False, False, 0)
applet.add(hbox)
applet.show_all()
gobject.type_register(Priberam)
def priberam_factory(applet,iid):
Priberam(applet,iid)
return True
if len(sys.argv) > 1 and sys.argv[1] == '-d': # debugging
mainWindow = gtk.Window()
mainWindow.set_title('Applet window')
mainWindow.connect("destroy", lambda w: gtk.main_quit())
applet = gnomeapplet.Applet()
priberam_factory(applet, None)
applet.reparent(mainWindow)
mainWindow.show_all()
gtk.main()
sys.exit()
if __name__ == '__main__':
gnomeapplet.bonobo_factory('OAFIID:GNOME_Priberam_Factory', gnomeapplet.Applet.__gtype__, 'Priberam Applet', '0.1', priberam_factory)
Thanks in advance
Solved...The solution was so simple...I just have to change the path to the image file to the complete path...instead of pixbuf = gtk.gdk.pixbuf_new_from_file('1.png') I should use for example: pixbuf = gtk.gdk.pixbuf_new_from_file('/home/username/applet/1.png')
Better: pixbuf = gtk.gdk.pixbuf_new_from_file(os.path.join(os.path.dirname(__file__), '1.png')), don't forget to import os

Categories

Resources