Ironpython integration .NET Framework

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
Antworten
spammi
User
Beiträge: 6
Registriert: Montag 30. März 2015, 14:59

Hallo zusammen ich habe da ein Problem, dass ich anscheinend nicht alleine gelöst bekomme...

Es geht um die Verwendung des .NET Framework in Ironpython.

Es geht um den folgenden Code:

Code: Alles auswählen

# -*- coding: utf-8 -*-
import clr
clr.AddReference("System.Drawing")
clr.AddReference("System.Windows.Forms")

from System.Windows.Forms import Application, Form, Button, Label, Screen, TextBox, AnchorStyles, DialogResult, AnchorStyles
from System.Drawing import ContentAlignment, Point


class Zeichnen():
	'''oProject = oDesktop.NewProject()
	oProject.InsertDesign("Maxwell 2D", "TestDesign", "Magnetostatic", "")
	oProject.Rename("MyProject", True)
	oProject = oDesktop.SetActiveProject("MyProject")
	oDesign = oProject.SetActiveDesign("TestDesign")'''

	def Init(*args):
#		qs,gfd  = args
		field = 13	                    
		R_outer_SY = RoS                 #<-----Hier sollen die ausgelesenen Werte Übergeben werden z.B. RoS
		R_inner_SY = 80.85
		R_outer_RY = 80
		GGap = R_inner_SY - R_outer_RY
		Slot_Height = 23.3182
		Top_Diameter = 7.75
		Slot_Opening = 3.0837
		Fillet_Tooth_Tip = 0.319
		Fillet_Tooth_Inner = 0.319
		Slot_Opening_Angle = 10.6335
		Tooth_Tip_Height = 0.82303
		Shaft_Radius = 24
		Stator_Slots = 48

#Klasse für die Auswahl der Eingabemethode
class Auswahl(Form):
	def __init__(self):
		creenSize = Screen.GetWorkingArea(self)
		FORMheight = 320 
		FORMwidth = 480
		self.Text = 'Eingabeformat'
		self.Height = FORMheight
		self.Width = FORMwidth
		label = Label(Top = 30, Left = 50, Height = 100, Width = 250)
		label.Text = '''Bitte auswählen:
		Parameterbasiert: Eingabe über Parameter.
		
		Manuell: Eingabe für jede Nut einzeln.'''
		
		param_button = Button(Text = "Parameterbasiert", Width = 200, Top = FORMheight - 150, Left = (FORMwidth / 2) - 100)
		
		manu_button = Button(Text = "Manuell", Width = 200, Top = FORMheight - 100, Left = (FORMwidth / 2) - 100)
		
		beenden_button = Button(Text = "Beenden", Top = 260, Left = 390)
		
		param_button.Click += self.OnClickParam
		manu_button.Click += self.OnClickManu
		beenden_button.Click += self.OnClickBeenden
		
		self.Controls.Add(label)
		self.Controls.Add(param_button)
		self.Controls.Add(manu_button)
		self.Controls.Add(beenden_button)
		
	def OnClickParam(self, *args):
		Param = ParamDialog()
		if Param.ShowDialog() == DialogResult.OK:
			#Zeichnen.Init()
			RoS = Param.RoS_Textbox.Text               #<----- Hier das Problem
			self.Close()
			
	
	def OnClickManu(self, *args):
		Manu = ManuDialog()
		Manu.ShowDialog()
		
	def OnClickBeenden(self, *args):
		self.Close()

#Klasse für die Eingabe über Parameter
class ParamDialog(Form):
	def __init__(self):
		self.Text ='Parameterbasiert'
		self.Height = 400
		self.Width = 600
		
		ueberschrift_label = Label(Text = "Bitte eingeben:", Top=10, Left=30)
		
		eingabe_label = Label(AutoSize = False, Top = 30, Height = 200, Width = 200, TextAlign = ContentAlignment.TopRight)
		eingabe_label.Text='''Außendurchmesser Stator, RoS(mm):
		
		Innendurchmesser Stator, RiS(mm):
		
		Stator Nutzahl, Qs:
		
		Polpaarzahl, p:
		
		Reihenwindungszahl, zQ:
		
		Schrittweite, y:
		
		Anzahl Schichten:'''
		
		RoS_Textbox = TextBox(Top = 27, Left = 200, Width = 150)
		
		RiS_Textbox = TextBox(Top = 52, Left = 200, Width = 150)
		
		Qs_Textbox = TextBox(Top = 77, Left = 200, Width = 150)
		
		p_Textbox = TextBox(Top = 102, Left = 200, Width = 150)
		
		zQ_Textbox = TextBox(Top = 127, Left = 200, Width = 150)

		y_Textbox = TextBox(Top = 152, Left = 200, Width = 150)

		schicht_Textbox = TextBox(Top = 177, Left = 200, Width = 150)

		eingabe_button = Button(Text = "Eingabe beenden", Width = 120, Location = Point(200, 210))

		zurueck_button = Button(Text = "zurück", Width = 120, Location = Point(200,240))
		
		#bestaetigen_button = Button(Text = "bestätigen", Location = Point(355,175))

		self.Controls.Add(eingabe_label)
		self.Controls.Add(ueberschrift_label)
		self.Controls.Add(RoS_Textbox)
		self.Controls.Add(RiS_Textbox)
		self.Controls.Add(Qs_Textbox)
		self.Controls.Add(p_Textbox)
		self.Controls.Add(zQ_Textbox)
		self.Controls.Add(y_Textbox)
		self.Controls.Add(schicht_Textbox)
		self.Controls.Add(eingabe_button)
		self.Controls.Add(zurueck_button)
		#self.Controls.Add(bestaetigen_button)
		
		zurueck_button.Click += self.OnClickZurueck
		
		eingabe_button.Click += self.OnClickEingabe
		
		#bestaetigen_button.Click += self.OnClickBestaetigen
		
	def OnClickZurueck(self, *args):
		self.Close()
			
	def OnClickEingabe(self, *args):
		self.DialogResult = DialogResult.OK
		RoS = form1.RoS_Textbox.Text                   
		self.Close()
Application.EnableVisualStyles()
form1 = Auswahl()
Application.Run(form1)
Das Problem ist:
Nach drücken des eingabe_button, soll die Form geschlossen werden(geht) und dann sollen die Werte aus den TextBoxes ausgelesen werden und in Variablen gespeichert werden(z.B. RoS_Textbox, geht nocht nicht :() hier habe ich anscheinend ein Problem mit dem Zugriff. Ich bekomme die Fehlermeldung: ParamDialog abject has no attribute "RoS_Textbox"... Aber das habe ich doch definiert: RoS_Textbox = TextBox(Top = 27, Left = 200, Width = 150).
Des Weiteren sollen diese ausgelesenen Variablen dann an die Klasse zeichnen übergeben werden.

Wahrscheinlich ist das Problem recht einfach zu lösen, aber OOP mit Python hab ich noch nicht so viel gemacht, habe nur mal einen C# Kurs besucht.

Vielen Dank für eure Hilfe. :D
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Du hast die Textbox an einen *lokalen* Namen gebunden (Z. 103)! Du fügst das Objekt an sich dann in Zeile 125 der GUI hinzu, damit es offenbar angezeigt werden kann, aber es wird dadurch ja nicht automatisch Attribut von ``ParamDialog``! Evtl. kannst Du über das Atribut ``controls`` wieder auf das Textbox-Objekt zugreifen (``get``?) Alternativ musst Du es zu einem Exemplar-Attribut machen!

Mal zur Verdeutlichung:

Code: Alles auswählen

class Foo: pass

class Container:
    
    def __init__(self):
        self.controls = []
        foo = Foo() # *lokaler* Name ``foo``!
        self.add(foo)
        
    def add(self, item):
        self.controls.append(item)
        
c = Container()
c.foo 

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-1-b9489a8163e4> in <module>()
     12
     13 c = Container()
---> 14 c.foo

AttributeError: 'Container' object has no attribute 'foo'
Aber:

Code: Alles auswählen

c.controls
[<__main__.Foo at 0x37f5830>]
Das Objekt gibt es natürlich noch - es ist aber nur noch über das Attribut ``controls`` von ``Container`` erreichbar. Nicht mehr über ``foo``, welches nur *lokal* im Scope von ``Container.__init__`` gültig ist.

Eine Lösung wäre folgende:

Code: Alles auswählen

class Foo: pass

class Container:
    
    def __init__(self):
        self.controls = []
        self.foo = Foo()
        self.add(self.foo)
        
    def add(self, item):
        self.controls.append(item)
        
c = Container()
c.foo
Dein Code ist übrigens schwer zu lesen und nicht gut strukturiert! Zum einen solltest Du weniger Leerzeilen einbauen, zum anderen PEP8 mehr beachten (Ok, Framework-Konventionen haben Vorrang vor klassischen Python-Bezeichnern; hier insbesondere bei Methodennamen, aber *innere* Namen können imho ruhig PEP8 kompatibel sein!)

Zudem solltest Du GUI und Fachlogik *trennen*! Deine Berechnung kann ich unter Linux nun nicht nutzen, weil da kein Windows-Forms nicht funktionieren - Gtk könnte ich aber nutzen ;-)

Ein weiterer Vorteil ist die bessere Testbarkeit!

Das gilt für C# übrigens genauso ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@Hyperion: Die GUI ”funktioniert” unter Linux, zumindest was die lauffähigkeit des Programms angeht, wenn man mal davon absieht das dieses absolut positionieren von GUI-Elementen ziemlich schlecht funktioniert und spätestens beim zweiten Dialog die Beschriftungen der Eingabefelder und die Eingabfelder selber immer weiter auseinanderdriften. Zumindest bei mir.

Ich kenne Windows Forms nicht — ist es da echt üblich immer noch alles von Hand zu positionieren statt Techniken zu verwenden die auch bei anderen Monitorauflösungen und -einstellungen als der eigenen funktionieren?
spammi
User
Beiträge: 6
Registriert: Montag 30. März 2015, 14:59

@Hyperion, vielen Dank für deine Antwort, mit Hilfe des Codes, habe ich es hinbekommen, die Werte aus den TextBoxes zu übergeben.
Das mit der Codestrukturierung könnte daran liegen, dass dies so nicht der ganz Code ist, sondern nur Teile die ich hier zusammengeschnitten habe(daher wahrscheinlich die Leerzeilen). Zum Thema GUI und Fachlogik trennen: Die ganz Logik steckt in der Klasse Zeichnen, welche hier nur teilweise aufgeführt ist, die anderen beider Klassen benutze ich nur, weil ich ein Script für das Simulationsprogramm Maxwell schreiben will, dort aber Eingaben nicht über die Konsole während des laufenden Scripts möglich sind, daher die GUI.


@BlackJack: Wie das mit den Windows Forms aussieht kann ich dir leider auch nicht sagen, aber für meine Zwecke reicht die feste Positionierung aus, da s.o. die GUI lediglich zur Eingabe von Daten dienen soll. Unter Windows, sind die Beschriftungen alle so wie sie sein sollen.
BlackJack

@spammi: Unter Windows generell oder bei *Deinem* Windows mit *Deiner* Monitorauflösung und *Deinen* Einstellungen? Auch unter Windows ist es möglich verschiedene Monitore mit unterschiedlichen Grössen und Auflösungen zu betreiben was zu unterschiedlichen Einstellungen zum Beispiel bei Schriftgrössen führt.
spammi
User
Beiträge: 6
Registriert: Montag 30. März 2015, 14:59

@BlackJack: Also generell kann ich nicht sagen, aber habs an 4 verschiedenen Monitoren mit verschiedenen Auflösungen getestet, und es hat funktioniert. Ich denke, es sollte mit allen Monitoren funktionieren, deren Auflösung größer als 480*320 ist, das ist die Fenstergröße.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

BlackJack hat geschrieben: Ich kenne Windows Forms nicht — ist es da echt üblich immer noch alles von Hand zu positionieren statt Techniken zu verwenden die auch bei anderen Monitorauflösungen und -einstellungen als der eigenen funktionieren?
Es gibt natürlich Layout-Manager ;-) Insofern: Nein!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

spammi hat geschrieben: Zum Thema GUI und Fachlogik trennen: Die ganz Logik steckt in der Klasse Zeichnen, welche hier nur teilweise aufgeführt ist, ...
Ah... ok. Na dann ist das ja zumindest grob getrennt :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@spammi: Ich würde sagen da denkst Du falsch denn wenn ich das in der Dokumentation richtig verstanden habe sind die Positionsangaben in Pixeln. Leute mit hohen Bildschirmauflösungen (in PPI/DPI) stellen in der Regel die Schriften grösser ein weil sonst alles viel zu klein dargestellt wird, und dann passen pixelgenau positionierte GUI-Elemente nicht mehr wie das bei Deinen Einstellungen der Fall ist. Die finden dann ein 480×320 Fenster insgesamt vielleicht ein bisschen zu klein. Die Zeiten das man davon ausgehen kann das jeder eine 96 DPI-Auflösung verwendet sind nun schon etwas länger vorbei. Auch unter Windows.

Und wenn es Layout-Manager gibt, wie in jedem anderen modernen GUI-Rahmenwerk, dann sollte man die vielleicht auch verwenden. Selbst bei nur einer Auflösung machen die einem das Leben einfacher wenn man etwas an der GUI verändern möchte und dafür nicht plötzlich viele Anzeigeelemente von Hand neu positionieren muss.
Antworten