zusammengesetzter Pfeil...

Plattformunabhängige GUIs mit wxWidgets.
Antworten
Benutzeravatar
Batt0sa1
User
Beiträge: 15
Registriert: Montag 21. April 2008, 23:15

Montag 21. April 2008, 23:40

Hi, mein erster Beitrag und erstmal Hallo an alle / Hello World,

ich versuche gerade einen Pfeil aus meheren einzelnen (wx.Pen) Strichen zu erzeugen.
Die einzelnen Striche sollen später von einem Übergabewert abhängig sein (momentan noch hart gecoded).
Falls es jemanden was sagt, es geht in die Richtung Sankey-Diagramm.

Die einzelnen Pfeile habe ich schon zusammengesetzt gekriegt, nun stellt sich die Frage, wie erstelle ich daraus einen Pfeil?
momentan sieht es so aus:

Bild

und mein Ziel wäre das hier (oder so ähnlich):

Bild

Mein Code:
(ich bin neu bei Python und relativ unerfahren, ich bitte um Nachsicht ;))
Die Kommentare waren i.d.R. Notizen für mich...
:)

Code: Alles auswählen

#!/usr/bin/pythonw
import wx

class DrawPanel(wx.Panel):

	def __init__(self, parent):
	    wx.Panel.__init__(self, parent, -1)
	    wx.EVT_PAINT(self, self.Strich)
	
	def OnPaint(self, list, St_x, St_y, En_x, En_y):
	    dc = wx.PaintDC(self)
	    #dc.Clear()
	    dc.SetPen(wx.Pen(list[0], list[1])) #Farbe, Breite
	    dc.DrawLine(St_x, St_y, En_x, En_y) # x1,y1 ,x2, y2
	    
	def Strich(self, event="none"):
		#Die Variablen mit Uebergabewerten loesen ;)
		Objects = [("nothing", 25, 'grey'), ("Apfel", 18, 'green'), ("Birne", 12, 'Blue'), ("Banane", 8, 'yellow')]
		St_x= 0
		St_y= 20
		En_x=200
		En_y= 20
		
  		for _ in Objects:

  		 #Die Luecke zwischen den Strichen kommt daher, weil wx.pen um die Koords "herum" zeichnet --> die y Werte stimmen nicht mehr --> Luecke
  		 list=[]
  		 list.insert(len(list),_[2])# Farbe Bsp.: list('RED', 5)
  		 list.insert(len(list),_[1])# Menge
  		 # um das drumherumzeichnen auszugleichen, nochmal die Haelfte dazu addieren
  		 St_y1 = St_y + list[1]/2
  		 En_y1 = En_y + list[1]/2
  		 
  		 self.OnPaint(list, St_x, St_y1, En_x, En_y1)
  		 St_y = St_y + list[1]
  		 En_y = En_y + list[1]
  		 print 'St_y: (in Haupt Fkt.)', St_y, 'fuer ', list
  		 #print 'Strich: ok'


if __name__ == "__main__":
  app = wx.PySimpleApp(0)
  frame = wx.Frame(None, -1, "TestSankey",
     size=(200, 100))
  DrawPanel(frame)
  frame.Show(True)
  app.MainLoop()

Ich wäre über jegliche Hilfe dankbar :D

Bisher hatte ich gedacht, entweder die Endwerte abzufangen und 2 Dreiecke mit Hintergrundfarben oder Alphawerten zu zeichnen, oder irgendwas zu nutzen, was mir aus dem einen Pfeil macht (Shape o.ä.?)

Würde mich absolut freuen wenn ihr mir weiterhelfen könntet :)
Benutzeravatar
Batt0sa1
User
Beiträge: 15
Registriert: Montag 21. April 2008, 23:15

Mittwoch 23. April 2008, 00:28

Nungut...
Ein wenig weiter bin ich jetzt ja :)
So sieht es gerade aus:

Bild

Der Code:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
    Modul:          Sankey
    Description:    creates (depending on return values 'Menge', start(St_x, St_y) and goal(En_x, En_y)) a sankey
    Version:        0.2a
    Copyright:      2008 by Robert Schröder 
    License:        GPL
    Requirements:   Python 2.5
""" 
import wx
import wx.lib.ogl as ogl

class DrawPanel(wx.Panel):
	def Clipping(self, Pf_y1, En_x, Pf_y2, laenge):
		Proz = En_x -laenge * 11 / 100
		Proz=int(Proz)
		dc = wx.PaintDC(self)
		#dc.SetBrush(wx.Brush('Red'))
		#dc.DrawRectangle(St_x, St_y, En_x, En_y)
		#pen=wx.Pen('black', 1) #Farbe, Breite
		#pen.SetCap(wx.CAP_BUTT) # fuer's Enden "abschneiden"
		#dc.SetPen(pen) 
		Mitte = ((Pf_y2-Pf_y1)/2 + Pf_y1)
		
		#Pfeil-Shape       
		points = (((En_x, Mitte), (En_x, Pf_y1), (Proz, Pf_y1),(En_x, Mitte), (En_x, Pf_y2), (Proz, Pf_y2)))
		Pfeil= wx.RegionFromPoints(points)
		dc.SetClippingRegionAsRegion(Pfeil)
		
		#Notlösung, wenn clipping nicht klappt: drüberzeichnen :)
		dc.SetBrush(wx.Brush('white'))
		rect = Pfeil.GetBox()
		dc.DrawRectangleRect(rect)
		dc.DestroyClippingRegion()
		#1.Dreieck
		#dc.DrawLine(En_x, Mitte, En_x, Pf_y1)
		#dc.DrawLine(En_x, Pf_y1, Proz_5, Pf_y1)
		#dc.DrawLine(En_x, Mitte, Proz_5, Pf_y1 )
		#2. Dreieck
		
		#dc.DrawLine(En_x, Mitte, En_x, Pf_y2)
		#dc.DrawLine(En_x, Pf_y2, Proz_5, Pf_y2)
		#dc.DrawLine(En_x, Mitte, Proz_5, Pf_y2 )
		
		#Pfeil2=[(En_x, Mitte) ,(En_x, Pf_y2) , (Proz_5, Pf_y2)]
		#clipping_unten = wx.RegionFromPoints(Pfeil2)
		#tria = clipping_unten.GetBox()
		#dc.SetClippingRegionAsRegion(clipping_unten)
		
		#dc.DestroyClippingRegion()
		#dc.DrawRectangle(90, 30, 50, 50)
		#region1 = wx.Region(80, 20, 50, 50)
		#region2 = wx.Region(90, 30, 50, 50)
		#region2.SubtractRegion(region1)
		#rect = region2.GetBox()
		#dc.SetClippingRegionAsRegion(region1)
		#dc.SetBrush(wx.Brush('Red'))
		#dc.DrawRectangleRect(rect)
		#dc.DestroyClippingRegion()

	def __init__(self, parent):
	    wx.Panel.__init__(self, parent, -1)
	    wx.EVT_PAINT(self, self.Strich)
	
	def OnPaint(self, Objects, zaehler, St_x, St_y, En_x, En_y):
	    dc = wx.PaintDC(self)
	    #dc.Clear()
	    pen=wx.Pen(Objects[zaehler][2], Objects[zaehler][1]) #Farbe, Breite
	    pen.SetCap(wx.CAP_BUTT) # fuer's Enden "abschneiden"

	    dc.SetPen(pen) 
	    dc.DrawLine(St_x, St_y, En_x, En_y) # x1,y1 ,x2, y2
	    
	def Strich(self, event="none"):
		#Die Variablen mit Uebergabewerten loesen ;)
		Objects = [("Luft", 25, 'grey'), ("Apfel", 18, 'green'), 
				   ("Birne", 12, 'Blue'), ("Banane", 8, 'yellow')]
		St_x= 0
		St_y= 20
		En_x=200
		En_y= 20
		Pf_y1 = St_y
		zaehler = 0		
  		for _ in Objects:

  		 #Die Liste wird erstellt, damit SetPen(s.o.) die Werte 'einfach' kriegt
  		 #Die Luecke zwischen den Strichen kommt daher, weil wx.pen um die Koords "herum" zeichnet --> die y Werte stimmen nicht mehr --> Luecke


  		 # um das drumherumzeichnen auszugleichen, nochmal die Haelfte dazu addieren
  		 St_y1 = St_y + _[1]/2
  		 En_y1 = En_y + _[1]/2

  		 self.OnPaint(Objects, zaehler, St_x, St_y1, En_x, En_y1)
  		   		 
  		 St_y = St_y + _[1]
  		 En_y = En_y + _[1]
  		 Pf_y2= En_y
  		 print 'St_y: (in Haupt Fkt.)', St_y, 'fuer ', Objects[zaehler][0], ' bei der Menge', Objects[zaehler][1] 
  		 #print 'Strich: ok'
  		 zaehler = zaehler + 1
  		#Pfeil (auf die Spitzen 2 Dreicecke zeichnen)
  		laenge = (En_x-St_x)
  		self.Clipping(Pf_y1, En_x, Pf_y2, laenge)
     


if __name__ == "__main__":
  app = wx.PySimpleApp(0)
  frame = wx.Frame(None, -1, "TestSankey",
     size=(200, 100))
  DrawPanel(frame)
  frame.Show(True)
  app.MainLoop()
Ein wenig verbessert (List und so ;))
Jedenfalls, würde ich gern Clipping einsetzen, nur irgendwie funktioniert das nicht...
Die Fkt. wx.PolygonShape hat bei mir nicht wirklich funktioniert :(
Kann es daran liegen, dass es in einer anderen Fkt. aufgerufen wird?
Also z.B. eine Schicht über den Strichen liegt und sie deshalb nicht partiell löscht?

Die Lösung die ich mir jetzt erdacht habe, ist ja auch mehr halbgar...
Wenn ich den Code richtig verstehe zeichne ich mir noch ein Viereck, welches nicht vollständig dargestellt wird (daher auch die schwarzen Randstriche)


Hat da jemand ne Idee?
Also eine Verbesserungsmöglichkeit, die er mir preisgeben möchte :D
sechsrad
User
Beiträge: 173
Registriert: Montag 31. März 2008, 17:09

Freitag 25. April 2008, 18:09

versuch mal "pygame" mit "wx" zu mischen. ist eine gute sache für die grafische darstellung.
Antworten