Zeichnung in PyGobject (python3)

Ich versuche, einfaches Grafikeditor mit PyGObject und Python 3 zu schreiben. Ich muss Linien mit unterschiedlicher Farbe und Breite mit der Maus zeichnen. Ich habe viele Beispiele gefunden, aber nichts komplexer.

Wie speichere ich das gezeichnete Bild zwischen "Draw" -Ereignissen? Gibt es eine inkrementelle Art zu zeichnen oder muss ich bei jedem "Draw" -Ereignis neu zeichnen? Ich habe herausgefunden, dass ich den Weg retten kann, aber wie kann ich die Breite und die Farben der gezeichneten Linien speichern? Gibt es da ein Bild außerhalb von 'Draw' Rückruf und nur gelten (ziehen) es innerhalb Callback?

Hier ist was ich jetzt habe

#!/usr/bin/env python # -*- coding: utf-8 -*- from gi.repository import Gtk, Gdk import os class App(object): main_ui = os.path.join(os.path.dirname(__file__), 'gui.glade') def __init__(self): self.builder = Gtk.Builder() self.builder.add_from_file(self.main_ui) self.main_window.connect('destroy', self.quit) self.mw_quit_button.connect('clicked', self.quit) self.mw_graph_editor_button.connect('clicked', self.show_window, self.graph_editor_window) self.graph_editor_window.connect('delete-event', self.hide_window_delete) self.ge_menubar_file_quit.connect('activate', self.hide_window, self.graph_editor_window) self.ge_toolbar_quit.connect('clicked', self.hide_window, self.graph_editor_window) self.ge_drawingarea.connect('motion-notify-event', self.pointer_motion) self.ge_drawingarea.connect('motion-notify-event', self.show_coordinates) self.ge_drawingarea.connect('draw', self.draw_callback) self.path = None self.coord = (0, 0) self.rgb = (0, 0, 0) def __getattr__(self, name): obj = self.builder.get_object(name) if not obj: raise AttributeError("Object {0} has no attribute {1}".format(self, name)) setattr(self, name, obj) return obj def draw_callback(self, drawingarea, cr): if self.path: cr.append_path(self.path) cr.line_to(self.coord[0], self.coord[1]) cr.set_source_rgba(*self.rgb) self.path = cr.copy_path_flat() cr.stroke() def show_coordinates(self, window, event): self.ge_mouse_coordinates.set_label('X: {0:.0f} Y: {1:.0f}'.format(event.x, event.y)) def pointer_motion(self, widget, event): if event.state & Gdk.ModifierType.BUTTON1_MASK: self.draw(widget, event.x, event.y) elif event.state & Gdk.ModifierType.BUTTON3_MASK: self.draw(widget, event.x, event.y, True) def draw(self, widget, x, y, erase=False): self.coord = (x,y) if erase: self.rgb = (256, 256, 256) else: self.rgb = (0, 0, 0) widget.queue_draw() def show_window(self, widget, data): data.show_all() def hide_window_delete(self, widget, event): widget.hide() return True def hide_window(self, widget, window): window.hide() def run(self): self.main_window.show_all() Gtk.main() def quit(self, widget=None, data=None): self.main_window.destroy() Gtk.main_quit() if __name__ == "__main__": app = App() app.run() 

Sorry für mein Englisch, es ist nicht meine Muttersprache.

One Solution collect form web for “Zeichnung in PyGobject (python3)”

Sie müssen eine Doppelpuffertechnik verwenden:

http://de.wikipedia.org/wiki/Multiple_buffering#Double_buffering_in_computer_graphics

Das ist ein Bild, und du zeichnet das Bild: das Bild ist der "hinter dem Kulissen" Puffer. Sie können viele Methoden haben, die etwas zu diesem Bild zeichnen. Dann, auf dem Rückruf, der auf "zeichnen" -Signal reagiert, das heißt, die Methode, die tatsächlich etwas in den Grafikspeicher zieht, werfen Sie einfach Ihr "hinter die Kulissen" Bild.

Theorie im Code ( Test.py ):

 import cairo from gi.repository import Gtk from os.path import abspath, dirname, join WHERE_AM_I = abspath(dirname(__file__)) class MyApp(object): """Double buffer in PyGObject with cairo""" def __init__(self): # Build GUI self.builder = Gtk.Builder() self.glade_file = join(WHERE_AM_I, 'test.glade') self.builder.add_from_file(self.glade_file) # Get objects go = self.builder.get_object self.window = go('window') # Create buffer self.double_buffer = None # Connect signals self.builder.connect_signals(self) # Everything is ready self.window.show() def draw_something(self): """Draw something into the buffer""" db = self.double_buffer if db is not None: # Create cairo context with double buffer as is DESTINATION cc = cairo.Context(db) # Scale to device coordenates cc.scale(db.get_width(), db.get_height()) # Draw a white background cc.set_source_rgb(1, 1, 1) # Draw something, in this case a matrix rows = 10 columns = 10 cell_size = 1.0 / rows line_width = 1.0 line_width, notused = cc.device_to_user(line_width, 0.0) for i in range(rows): for j in range(columns): cc.rectangle(j * cell_size, i * cell_size, cell_size, cell_size) cc.set_line_width(line_width) cc.set_source_rgb(0, 0, 0) cc.stroke() # Flush drawing actions db.flush() else: print('Invalid double buffer') def main_quit(self, widget): """Quit Gtk""" Gtk.main_quit() def on_draw(self, widget, cr): """Throw double buffer into widget drawable""" if self.double_buffer is not None: cr.set_source_surface(self.double_buffer, 0.0, 0.0) cr.paint() else: print('Invalid double buffer') return False def on_configure(self, widget, event, data=None): """Configure the double buffer based on size of the widget""" # Destroy previous buffer if self.double_buffer is not None: self.double_buffer.finish() self.double_buffer = None # Create a new buffer self.double_buffer = cairo.ImageSurface(\ cairo.FORMAT_ARGB32, widget.get_allocated_width(), widget.get_allocated_height() ) # Initialize the buffer self.draw_something() return False if __name__ == '__main__': gui = MyApp() Gtk.main() 

Glade-Datei ( Test.glade ):

 <?xml version="1.0" encoding="UTF-8"?> <interface> <!-- interface-requires gtk+ 3.0 --> <object class="GtkWindow" id="window"> <property name="can_focus">False</property> <property name="window_position">center-always</property> <property name="default_width">800</property> <property name="default_height">600</property> <signal name="destroy" handler="main_quit" swapped="no"/> <child> <object class="GtkDrawingArea" id="drawingarea1"> <property name="visible">True</property> <property name="can_focus">False</property> <signal name="draw" handler="on_draw" swapped="no"/> <signal name="configure-event" handler="on_configure" swapped="no"/> </object> </child> </object> </interface> 

Abhängigkeiten:

Python 2:

 sudo apt-get install python-cairo 

Python 3:

 sudo apt-get install python3-gi-cairo 

Jetzt ausführen mit:

 python test.py 

oder

 python3 test.py 

Wie es aussieht:

Bildbeschreibung hier eingeben

Alle Unterlagen für Kairo finden Sie unter http://cairographics.org/documentation/pycairo/3/reference/index.html

Das oben ist ein Port eines Beispiels, das ich in C vor langer Zeit für Gtk 2.16 gemacht habe, kannst du es auch überprüfen, ist aber auf Spanisch:

http://carlos.jenkins.co.cr/gtkcairo

Mit freundlichen Grüßen

  • Python matplotlib Installation Problem
  • So speichern Sie Int in eine Textdatei
  • Ist es möglich, den Operator ('=') in Python zu überschreiben?
  • "Richtiger Weg", um mehrere Versionen von Python auf archlinux zu verwalten
  • Fehler bei der Installation von uwsgi auf ubuntu mit python 3.5 mit pip
  • Gibt es einen Grund, nicht zu senden super () .__ init __ () ein Wörterbuch anstelle von ** kwds?
  • 'Collectstatic' Befehl schlägt fehl, wenn WhiteNoise aktiviert ist
  • Wie ändere ich den Hintergrund eines Rahmens in Tkinter?
  • Konvertieren (decodieren) Hex-String nach ASCII oder irgendein anderes verständliches Format
  • Rückgabewert von einem Python-Skript zu einem anderen
  • Wie kann ich eine Auswahl ausführen?
  • Python ist die beste Programmiersprache der Welt.