Bind an ein device context Objekt

Plattformunabhängige GUIs mit wxWidgets.
Antworten
Benutzeravatar
Mawilo
User
Beiträge: 452
Registriert: Sonntag 22. Februar 2004, 10:58
Wohnort: Sachsen
Kontaktdaten:

Hallo,

die Fragen gehen mir nicht aus ... :lol:

Ich möchte an eine gezeichnete Linie ein Event binden. Sobald der Mousecursor die Linie berührt, soll ein Popup-Fenster erscheinen. Geht so etwas mit wx?

Hier mal ein Beispielcode:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import wx

class MainFrame(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        bmpsize = (500, 500)
        self.bmp = self.get_base_bitmap(bmpsize)
        self.Bind(wx.EVT_PAINT, self.on_paint)
        self.SetSizeHintsSz(bmpsize)
        
    def get_base_bitmap(self, size):
        bmp = wx.EmptyBitmap(*size)
        dc = wx.MemoryDC(bmp)
        dc.SetBackground(wx.WHITE_BRUSH)
        dc.Clear()
        dc.SelectObject(wx.NullBitmap)
        return bmp
        
    def on_paint(self, event):
        dc = wx.BufferedPaintDC(self, self.bmp, style = wx.BUFFER_VIRTUAL_AREA)
        self.drawLine(dc)
        
    def drawLine(self, dc):
        color = 'blue'
        dc.SetPen(wx.Pen(color,width=2, style=wx.SOLID))
        line = dc.DrawLine(50, 50, 350, 200)
        #line.Bind(wx.EVT_ENTER_WINDOW, self.onEnterLine)
        #line.Bind(wx.EVT_LEAVE_WINDOW, self.onLeaveLine)
        
    def onEnterLine(self, event):
        sleep(0.25)
        pos = self.GetPosition()
        mousex = wx.MouseEvent.GetX(event) + pos[0]
        mousey = wx.MouseEvent.GetY(event) + pos[1] + 100
        self.popup = Popupwindow(mousex, mousey) 
        
    def onLeaveLine(self, event):
        self.popup.Destroy()

            
def main():
    app = wx.PySimpleApp()
    frame = wx.Frame(parent=None)
    x = MainFrame(frame)
    frame.Show()
    app.MainLoop()

if __name__ == '__main__':
    main()
Wenn ich die Zeilen 30 und 31 aktiviere, bekomme ich folgende Fehlermeldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "./testdatei.py", line 24, in on_paint
    self.drawLine(dc)
  File "./testdatei.py", line 30, in drawLine
    line.Bind(wx.EVT_ENTER_WINDOW, self.onEnterLine)
AttributeError: 'NoneType' object has no attribute 'Bind'
Hat jemand eine Idee für mich?

Grüße
Mawilo
BlackJack

Soweit ich weiss geht das nicht. Diese Grafiken sind Pixelgrafiken. Wenn die Punkte gezeichnet sind, weiss `wx` nichts mehr davon dass sie mal von einer Linie stammten.
Benutzeravatar
Mawilo
User
Beiträge: 452
Registriert: Sonntag 22. Februar 2004, 10:58
Wohnort: Sachsen
Kontaktdaten:

Na das ist aber keine gute Nachricht :cry:

Gibt es eine andere Möglichkeit, mit wx zu Zeichnen und an die Objekte eine Funktion zu binden? Ich benötige das für ein Weg-Zeit Diagramm.

Mawilo
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

Mawilo hat geschrieben:Na das ist aber keine gute Nachricht :cry:

Gibt es eine andere Möglichkeit, mit wx zu Zeichnen und an die Objekte eine Funktion zu binden? Ich benötige das für ein Weg-Zeit Diagramm.

Mawilo
Vielleicht geht das mit der Abfrage von Mouse Move Events (wx.EVT_MOTION). Jedoch müsstest du die Koordinaten irgendwie speichern. Ist glaube ich auch nicht wirklich einfach und/oder zielführend. *shrug*

Wart: Sieh dir doch aus dem Demo (aus dem Sample) Verzeichnis das pysketch an. Da wird das Objekt erkannt, wenn man mit der Maus draufklickt. Vielleicht bringt es dich weiter.
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

Hallo Mawilo...

evtl koennte auch OGL etwas fuer dich sein... auch dazu gibts ne gute DemoApp.
Ansonsten fallen mir jetzt noch zwei Moeglichkeiten ein:

Du nimmst Panels, die der Linie entsprechen. Die haben dann entsprechende Events, koennen aber nicht beliebig gedreht und geformt werden (nur waage- oder senkrecht eben).

Du fragst - wie schon mal vorgeschlagen - die Position der Mouse ab. Das koenntest du durch ein WindowEnterEvent ausloesen und durch ein WindowLeaveEvent beenden lassen das an das Panel gebunden ist, auf dem du deinen Graphen zeichnest.

Gruß
NKoehring
[url=http://www.python-forum.de/post-86552.html]~ Wahnsinn ist auch nur eine andere Form der Intelligenz ~[/url]
hackerkey://v4sw6CYUShw5pr7Uck3ma3/4u7LNw2/3TXGm5l6+GSOarch/i2e6+t2b9GOen7g5RAPa2XsMr2
Benutzeravatar
Mawilo
User
Beiträge: 452
Registriert: Sonntag 22. Februar 2004, 10:58
Wohnort: Sachsen
Kontaktdaten:

Na da werde ich doch mal schauen, ob ich es irgendwie hinbekomme. Vielen Dank erst mal für die Anregungen.

Mawilo
Benutzeravatar
Mawilo
User
Beiträge: 452
Registriert: Sonntag 22. Februar 2004, 10:58
Wohnort: Sachsen
Kontaktdaten:

Ich habe mir nun überlegt, für jede Linie ein Panel zu erstellen - was mich zum nächsten Problem führt.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import wx

class MainFrame(wx.Frame):
    def __init__(self, parent=None):
        wx.Frame.__init__(self, parent, -1, 'Test')
        drawpanel = wx.Panel(self)
        lines = [[(60, 60, 250, 200), 'red'], 
                 [(250, 50, 50, 200), 'blue'], 
                 [(100, 100, 290, 190), 'green']
                 ]
        obj = DrawObject(drawpanel)
        for idx, line in enumerate(lines):
            obj.drawLine(line[0], line[1], idx)

class DrawObject:
    def __init__(self, drawpanel):
        self.drawpanel = drawpanel
        
    def getPositionData(self, values):
        x1, y1, x2, y2 = values
        self.width = (x2 - x1 if x2 > x1 else x1 - x2)
        self.height = y2 - y1
        self.x = (x1 if x1 < x2 else x2)
        self.y = y1

    def drawLine(self, linevalues, colour, idx):
        self.colour = colour
        self.getPositionData(linevalues)
        self.panel = wx.Panel(self.drawpanel, -1, size=(self.width, self.height), pos=(self.x, self.y))
        self.panel.Bind(wx.EVT_PAINT, self.on_paint)
        #self.on_paint()
        print 'Funktionsaufruf %s'%(idx + 1)
        
    def on_paint(self, event=None):
        bmpsize = (self.width, self.height)
        bmp = self.get_base_bitmap(bmpsize)
        dc = wx.BufferedPaintDC(self.panel, bmp, style = wx.SOLID)
        dc.SetPen(wx.Pen(self.colour, width=2, style=wx.SOLID))
        dc.DrawLine(self.x, self.y, self.width, self.height)
        print self.x, self.y, self.width, self.height, self.colour

    def get_base_bitmap(self, size):
        bmp = wx.EmptyBitmap(*size)
        dc = wx.MemoryDC(bmp)
        dc.SetBackground(wx.WHITE_BRUSH)
        dc.Clear()
        dc.SelectObject(wx.NullBitmap)
        return bmp

def main():
    app = wx.PySimpleApp()
    frame = MainFrame()
    frame.Show()
    app.MainLoop()

if __name__ == '__main__':
    main()
Rufe ich die Funktion on_paint über Bind(Zeile 33) auf, so erhalte ich folgende Print-Ausgabe:

Code: Alles auswählen

Funktionsaufruf 1
Funktionsaufruf 2
Funktionsaufruf 3
100 100 190 90 green
100 100 190 90 green
Aktiviere ich stattdessen die Zeile 34 sieht die print-Ausgabe so aus:

Code: Alles auswählen

60 60 190 140 red
Funktionsaufruf 1
50 50 200 150 blue
Funktionsaufruf 2
100 100 190 90 green
Funktionsaufruf 3
Im ersten Fall wird dabei ein Panel gezeichnet. Eine Linie ist in keinem Fall zu sehen.

Wie bekomme ich für jede Linie ein Panel hin, wo die Linie auch angezeigt wird?

Mawilo
Antworten