I'm working on a transparent window which includes a DrawingArea widget, which gets on top with a solid background color, but I want to keep it transparent. I've tried everything, unfortunately the docs are a bit dated (with PyGTK on the top results). Other things I've done is connecting its draw event as I'm doing it with the window, but with no success.
Of course I need the square to be shown, so I just need the background color to transparent. I've also tried with modify_bg, but I only manage to set it to solid colors.
Here's what I have so far.
#!/usr/bin/env python
from gi.repository import Gtk, Gdk
import cairo
class GWin (Gtk.Window):
def __init__(self):
super(GWin, self).__init__()
self.set_position(Gtk.WindowPosition.CENTER)
self.screen = self.get_screen()
self.visual = self.screen.get_rgba_visual()
if self.visual != None and self.screen.is_composited():
self.set_visual(self.visual)
self.connect("draw", self.on_win_draw)
self.set_app_paintable(True)
self.show_all()
self.draw_area = Gtk.DrawingArea()
self.draw_area.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
self.draw_area.connect('draw', self.begin_draw)
self.draw_area.show()
self.add(self.draw_area)
def begin_draw(self, draw_area, cairo_context):
cairo_context.rectangle(20, 20, 120, 120)
cairo_context.stroke()
def on_win_draw(self, widget, cr):
cr.set_source_rgba(1, 1, 1, 0.1)
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.paint()
cr.set_operator(cairo.OPERATOR_OVER)
win = GWin()
win.connect('delete-event', Gtk.main_quit)
Gtk.main()
You need to set the cairo.Context source rgba before creating the rectangle. Here is the code, the edited line marked with ### ADDED THIS LINE:
#!/usr/bin/env python
from gi.repository import Gtk, Gdk
import cairo
class GWin (Gtk.Window):
def __init__(self):
super(GWin, self).__init__()
self.set_position(Gtk.WindowPosition.CENTER)
self.screen = self.get_screen()
self.visual = self.screen.get_rgba_visual()
if self.visual != None and self.screen.is_composited():
self.set_visual(self.visual)
self.connect("draw", self.on_win_draw)
self.set_app_paintable(True)
self.show_all()
self.draw_area = Gtk.DrawingArea()
self.draw_area.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
self.draw_area.connect('draw', self.begin_draw)
self.draw_area.show()
self.add(self.draw_area)
def begin_draw(self, draw_area, cairo_context):
cairo_context.set_source_rgba(1, 1, 1, 1) ### ADDED THIS LINE
cairo_context.rectangle(20, 20, 120, 120)
cairo_context.stroke()
def on_win_draw(self, widget, cr):
cr.set_source_rgba(1, 1, 1, 0.1)
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.paint()
cr.set_operator(cairo.OPERATOR_OVER)
win = GWin()
win.connect('delete-event', Gtk.main_quit)
Gtk.main()
Related
I have a python 2 project using GTK2.
I am working on this project to migrate python 2 to python 3 and Gtk2 to Gtk 3.
I have a problem with the Gtk migration.
I want to replace “gdk. Pixmap” in my code.
I found this documentation:
Replace GdkPixmap by cairo surfaces The GdkPixmap object and related
functions have been removed. In the Cairo-centric world of GTK 3,
Cairo surfaces take over the role of pixmaps.
I have to use Cairo, but I don’t know how.
I spent a lot of time looking for examples in python. I didn’t find anything that matched my code.
Can someone help me, give me references?
Python2 :
class TraceView(gtk.DrawingArea):
…
def configure_event(self, widget, event):
_, _, width, height = widget.get_allocation()
self.pixmap = Pixmap(widget.window, width, height)
self.pixmap.draw_rectangle(widget.get_style().white_gc, True, 0, 0, width, height)
...
return True
def expose_event(self, widget, event):
x, y, width, height = event.area
widget.window.draw_drawable(widget.get_style().fg_gc[gtk.STATE_NORMAL],
self.pixmap, x, y, x, y, width, height)
self.maj_exposed()
...
return False
Python3 :
class TraceView(Gtk.DrawingArea):
…
def configure_event(self, widget, event):
width = widget.get_allocated_width()
height = widget.get_allocated_height()
self.pixmap = ?
self.pixmap. … ?
...
return True
def draw(self, widget, event):
???
self.maj_exposed()
...
return False
This is a minimal example of gtk3 program that draws a rectangle
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class MinimalCairoTest(Gtk.Window):
def __init__(self):
super(MinimalCairoTest, self).__init__()
self.set_size_request(400, 400)
self.connect("destroy", Gtk.main_quit)
darea = Gtk.DrawingArea()
darea.connect("draw", self.__draw_cb)
self.add(darea)
self.show_all()
def __draw_cb(self, widget, cairo_context):
cairo_context.set_source_rgb(1.0, 0.0, 0.0)
cairo_context.rectangle(20, 20, 120, 80)
cairo_context.fill()
MinimalCairoTest()
Gtk.main()
You can find more examples about how to draw with cairo here https://seriot.ch/pycairo/ and documentation here https://pycairo.readthedocs.io/en/latest/reference/context.html
I'm about to create a desktop based widget application using python via the gi.repository and the Gtk/Gdk v3.0. The goal is to have the window taking the whole screen being transparent, frameless and not accepting any focus. In addition it should be shown in every workspace and kept bellow any other window. After spending a long time I figured it out with the following code, yet with a drawback, the window has a vertical white line to the right side (kind of a border). So is there any solution to get rid of this line?
Os: Ubuntu 18.04
Python: 3.6
Screenshot
ui.py
import screeninfo
import gi
try:
gi.require_version("Gtk", "3.0")
gi.require_version("Gdk", "3.0")
gi.require_foreign("cairo")
except ImportError:
print("No Gtk v3.0 or pycairo integration")
from gi.repository import Gtk, Gdk, GLib
class Window (Gtk.Window):
def __init__ (self, canvas):
Gtk.Window.__init__(self)
self.set_skip_pager_hint(True)
self.set_skip_taskbar_hint(True)
self.set_type_hint(Gdk.WindowTypeHint.DESKTOP)
self.set_decorated(False)
self.set_keep_below(True)
self.set_accept_focus(False)
self.set_can_focus(False)
width = 500
height = 500
for monitor in screeninfo.get_monitors():
if monitor.is_primary:
width = monitor.width
height = monitor.height
# Todo: remove the annoying white border line on the right
self.set_size_request(width, height)
#Set transparency
screen = self.get_screen()
rgba = screen.get_rgba_visual()
self.set_visual(rgba)
self.override_background_color(Gtk.StateFlags.NORMAL, Gdk.RGBA(0, 0, 0, 0))
drawingarea = Gtk.DrawingArea()
self.add(drawingarea)
drawingarea.connect('draw', canvas.draw)
self.connect('destroy', Gtk.main_quit)
self.show_all()
self.move(0, 0)
def launch (self):
GLib.timeout_add_seconds(1, self.refresh)
Gtk.main()
return True
def refresh (self):
self.queue_draw()
return True
canvas.py
import cairo
FONT = 'UbuntuCondensent'
SLANT = cairo.FONT_SLANT_NORMAL
BOLD = cairo.FONT_WEIGHT_NORMAL
def draw (da, ctx):
ctx.set_source_rgb(1, 1, 1)
ctx.select_font_face(FONT, SLANT, BOLD)
ctx.set_font_size(32)
ctx.move_to(100, 100)
ctx.text_path('Hi There!')
ctx.fill()
main.py
import signal
import ui
import canvas
def main ():
signal.signal(signal.SIGINT, signal.SIG_DFL)
win = ui.Window(canvas)
win.launch()
if __name__ == '__main__':
main()
I want to get the characters printed only in blue.
How to do it?
Here is the sample program code, which is a fragment of most of the program.
I would be very grateful for your help.
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk
class TextViewWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="awesome gui")
self.set_resizable(True)
self.set_default_size(700, 550)
self.grid = Gtk.Grid()
self.add(self.grid)
self.create_textview()
self.buffer = []
def create_textview(self):
scrolledwindow = Gtk.ScrolledWindow()
scrolledwindow.set_hexpand(True)
scrolledwindow.set_vexpand(True)
self.grid.attach(scrolledwindow, 0, 2, 80, 1)
self.textview = Gtk.TextView()
scrolledwindow.add(self.textview)
self.textbuffer = self.textview.get_buffer()
self.textview.set_editable(False)
self.textview.set_cursor_visible(False)
self.textview.connect("key-press-event", self.on_key_down)
def on_key_down(self, widget, event, data=None):
znak_p = event.string
end_iter_m = self.textbuffer.get_iter_at_line_offset(1, 1)
qwerty_tag = self.textbuffer.create_tag(None, editable=True, foreground="blue")
self.textbuffer.insert_with_tags(end_iter_m, znak_p, qwerty_tag)
win = TextViewWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
Your on_key_down handler is wrong:
you are creating an anonymous tag every time you're pressing a key
you are using an invalid string for the GtkTextTag:foreground property
you are not returning a value from the callback telling GTK whether you handled the event (and thus should stop the event propagation) or not.
The GtkTextTag:foreground property uses the same format as the gdk_rgba_parse() function; if you want a blue color, you should use rgba(0.0, 0.0, 1.0, 1.0) instead of "blue".
A correct handler is:
def on_key_down(self, widget, event, data=None):
znak_p = event.string
end_iter_m = self.textbuffer.get
self.textbuffer.insert_with_tags(end_iter_m, znak_p, self.qwerty_tag)
return True
It makes a while that I've been trying to put a drawing area on a scrolled window. I've been reading articles about pygtk and C solutions but I think that they are not working in pyGobject.
I made a minimal example:
from gi.repository import Gtk, Gdk
import cairo
class Test(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
sw=Gtk.ScrolledWindow()
vp=Gtk.Viewport()
box=Gtk.VBox()
vp.set_size_request(100,100)
for i in range(3):
da=Gtk.DrawingArea()
da.connect("draw", self.draw, [0.3, 0.4, 0.6], da)
da.set_size_request(100,100)
box.add(da)
sw.add(vp)
vp.add(box)
self.add(sw)
self.show_all()
def draw(self, widget, event, color, da):
cr = widget.get_property('window').cairo_create()
cr.rectangle(0, 0, 100, 100)
cr.set_source_rgb(color[0], color[1], color[2])
cr.fill()
main=Test()
Gtk.main()
So the problem is that the drawing areas are not always rendered. This is for example, a gtk2 working code:
import gtk, cairo
class Test(gtk.Window):
def __init__(self):
gtk.Window.__init__(self)
sw=gtk.ScrolledWindow()
vp=gtk.Viewport()
box=gtk.VBox()
for i in range(3):
da=gtk.DrawingArea()
da.connect("expose-event", self.draw, [0.3, 0.4, 0.6], da)
box.add(da)
sw.add(vp)
vp.add(box)
self.add(sw)
self.show_all()
def draw(self, widget, event, color, da):
cr = widget.get_property('window').cairo_create()
cr.rectangle(0, 0, 100, 100)
cr.set_source_rgb(color[0], color[1], color[2])
cr.fill()
main=Test()
gtk.main()
Please do not point me to the following articles, I've already read them multiple times!
Gtk Forum: 1652
SO
AskUbuntu
pyGtk faq
I've added the viewport and a size_request, what else could be missing?
Thanks for the help!
by Emmanuele over the Gtk mailing list:
from gi.repository import Gtk, Gdk
import cairo
class Test(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
sw=Gtk.ScrolledWindow()
vp=Gtk.Viewport()
box=Gtk.VBox()
vp.set_size_request(100,100)
for i in range(3):
da=Gtk.DrawingArea()
da.connect("draw", self.draw, [0.3, 0.4, 0.6])
da.set_size_request(100,100)
box.add(da)
sw.add(vp)
vp.add(box)
self.add(sw)
self.show_all()
def draw(self, widget, cr, color):
cr.rectangle(0, 0, 100, 100)
cr.set_source_rgb(color[0], color[1], color[2])
cr.fill()
cr.queue_draw_area(0, 0, 100, 100)
return True
main=Test()
Gtk.main()
You should read the API reference for GTK+ 3.x:
https://developer.gnome.org/gtk/stable
as well as the Python API reference:
http://lazka.github.io/pgi-docs/#Gtk-3.0
You can add a damage region and force the redraw, I've slightly modified you example (sorry I could not resist fixing a couple of things) and add the queue_draw_area
I would strongly suggest avoid using a Gtk.DrawingArea and using a canvas widget instead, drawing on a canvas it's just much easier, GooCanvas is a good example but there are many others that you can use.
from gi.repository import Gtk, Gdk
import math, cairo
class Test(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
sw=Gtk.ScrolledWindow()
box=Gtk.VBox()
for i in range(3):
da=Gtk.DrawingArea()
da.connect("draw", self.draw, [0.3, 0.4, 0.6], da)
da.set_size_request(100,100)
box.pack_start(da, True, True, 10)
sw.add(box)
self.add(sw)
self.connect("destroy", Gtk.main_quit)
self.show_all()
def draw(self, widget, event, color, da):
cr = widget.get_property('window').cairo_create()
lg1 = cairo.LinearGradient(0.0, 0.0, 100, 0)
lg1.add_color_stop_rgb(0, color[0], color[1], color[2])
lg1.add_color_stop_rgb(1, color[0], color[1], color[2])
cr.rectangle(0, 0, 100, 100)
cr.set_source(lg1)
cr.fill()
da.queue_draw_area(0, 0, 100, 100)
main=Test()
Gtk.main()
I'm making a Gtk.Window using PyGi Gtk3 and It adds an annoying border around widgets and the main window:
The border is this grey border between the two images and in the outside of the window. Anyone knows how to completely remove it? So the two images could be seamless joint together.
This is my code:
#!/usr/bin/python3
#encoding:utf-8
from gi.repository import Gtk, Gdk
class TestMainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Test Window")
self.set_resizable(False)
self.box = Gtk.Box(orientation='vertical')
self.add(self.box)
self.album_cover = Gtk.Image()
self.album_cover.set_from_file('../reference/album-cover.jpg')
self.box.pack_start(self.album_cover, True, True, 0)
self.album_cover2 = Gtk.Image()
self.album_cover2.set_from_file('../reference/album-cover.jpg')
self.box.pack_end(self.album_cover2, True, True, 0)
def main():
win = TestMainWindow()
win.connect('delete-event', Gtk.main_quit)
win.show_all()
Gtk.main()
if __name__ == '__main__':
main()
Give a try at setting the "margins" property inherited from GtkWidget to FALSE. In C this is done using g_object_set.