Drawing in PyGobject (python3)

后端 未结 1 1811
北恋
北恋 2020-12-19 17:16

I\'m trying to write simple graphic editor using PyGObject and python 3. I need to draw lines with different color and width using mouse. I found many examples like this but

相关标签:
1条回答
  • 2020-12-19 17:45

    You need to use a Double Buffer technique:

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

    That is you have an image, and you draw over that image: that image is the "behind the scenes" buffer. You can have a lot of methods that draw something to that image. Then, on the callback that responds to 'draw' signal, that is, the method that actually draws something to the graphics memory you just throw your "behind the scenes" image.

    Theory in 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 file (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>
    

    Dependencies:

    Python 2:

    sudo apt-get install python-cairo
    

    Python 3:

    sudo apt-get install python3-gi-cairo
    

    Now execute with:

    python test.py
    

    or

    python3 test.py
    

    What it looks like:

    enter image description here

    All the documentation for cairo can be found in http://cairographics.org/documentation/pycairo/3/reference/index.html

    Kind regards

    0 讨论(0)
提交回复
热议问题