与派生的 IronPython Windows 中的表单控件交互 class

Interacting with Windows Form controls in derived IronPython class

我正在学习如何将 IronPython 与 C# 结合使用。我想将一个简单的 windows 表单合并到我的应用程序中,因此我决定将它们放在一个单独的 C# 项目中,并将其编译为我在 python 项目中引用的 dll。我想创建引用 windows 形式 class 的子 class,以便我可以在 python 中创建事件处理程序。现在我有了第一步:

import clr
import sys
import threading 
import random
import time


clr.AddReference('System.Drawing')
clr.AddReference('System.Windows.Forms')
clr.AddReference('CustomForm')

from System.Drawing import *
from System.Windows.Forms import * 
from System.IO import *
from System import EventHandler
from CustomForm import *
from threading import Lock, Semaphore, Thread
from Queue import PriorityQueue


#Set up some global variables
NUM_DOCTORS = 3
MAX_CAPACITY = 10
PRIORITY_HIGH = 1
PRIORITY_MEDIUM = 2
PRIORITY_LOW = 3
PRIORITY_NONE = -1

#TODO: Fix all print statements once form can be referenced 

class MyForm(Form1):

    def __init__(self):
        # Create child controls and initialize form
        super(MyForm, self).__init__()
        self.InitializeComponent()
        self.input_button.Click += self.input_button_Click
        print "Here right now"
        self.admin = None
        self.started = False

    def setAdmin(self, ad):
        self.admin = ad

    def input_button_Click(self, sender, e):
        print "hello click"
        if not self.started:
            self.admin.start()
            self.started = not self.started

        name = self.input_box.Text
        #acquire the lock here, can't do it in the method or it will block
        self.admin.lock.acquire()
        self.admin.addPatient(name)
        self.admin.lock.release()
        print "is this working?"
        self.input_box.Clear()




class Patient():

    def __init__(self, patient_name):
        #set up the severity of the illness   
        self.name = patient_name
        #set up illness -> random time from 1-60 seconds
        self.illness = random.randint(1,60)
        self.priority = random.randint(1,3)


    def getIllness(self):
        return self.illness

    def getName(self):
        return self.name

    def getPriority(self):
        return self.priority


class Doctor(Thread):

    def __init__(self, administrator, patient = None):
        self.curr_patient = patient
        self.admin = administrator

    def healPatient(self):
        sleep_time = self.curr_patient.getIllness()
        #heal the patient by sleeping with how long it takes to cure illness 
        time.sleep(sleep_time)


    def setPatient(self, patient):
        self.curr_patient = patient

    def run(self):
        #grab a patient, heal them, and report the results 
        self.curr_patient = self.admin.getPatientFromQueue()
        healPatient()
        self.admin.reportResults(self.curr_patient)




class Administrator(Thread):

    def __init__(self, form):
        self.num_doctors = NUM_DOCTORS
        self.lock = Lock()
        self.patient_queue = PriorityQueue()
        self.hospital_status = []
        self.parent = form
        self.waiting_room = []
        #potential replacement for pq.qsize()
        self.num_patients = 0

    def run(self):
        #first time
        for i in range(NUM_DOCTORS):
            d = Doctor(self)
            d.start()
            num_doctors -= 1


    def getPatientFromQueue(self):
        #grab a patient from the queue safely 
        if self.patient_queue.qsize() >= 1:
            return patient_queue.get()
        else: 
            return None


    def reportResults(self, patient):
        #update master list
        with self.lock:
            self.hospital_status.remove(patient)
            self.admitPatient()
            #change this for outcome
            self.parent.status_box.Text += "\n" + patient.getName() + " is released"
            printStatus()
            self.num_doctors += 1

            while self.num_doctors < 0:
                d = Doctor(self)
                d.start()
                self.num_docters -= 1



    def addPatient(self, name):
        #add a patient if possible
        p = Patient(name)
        if len(self.hospital_status) < MAX_CAPACITY:
            self.hospital_status.append(p)
            self.patient_queue.put((p, p.getPriority()))
            self.parent.status_box.Text += "\nPlease come in."    
        else:
            #check the waiting list
            self.waiting_room.append(p)
            self.parent.status_box.Text += "\nPlease take a seat in the waiting room."

    def admitPatient(self):
        #check the waiting room -> admit patient if there otherwise do nothing
        if len(self.waiting_room) > 0:
            p = self.waiting_room.pop()
            self.addPatient(p)



    def printStatus(self):       
        #only called when lock is had
        for p in self.hospital_status:
            self.parent.status_box.Text += p.getName() + "-Priority-" + p.getPriority()
            #print p.getName() + "-Priority-" + p.getPriority()



Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault(False)

form = MyForm()
admin = Administrator(form)
form.admin = admin



Application.Run(form)

我自己的表单只是 Form1,并由 python class MyForm 继承。当我 运行 这样做时,我在 C# 中制作的表单可以正确显示,但我找不到我应该如何与控件进行交互。表格显示为:

我希望能够听到按下按钮的声音并从顶部的文本框中读取内容。状态将打印在较大的富文本框中。我真的很感激任何意见。提前致谢!

更新 1:我认为我的问题的答案与找到的答案类似 here。我已将我的组件和方法的访问修饰符更改为 public,现在它们出现了。如果我的问题得到解决,我会更新这个。

更新 2:我现在可以看到这些组件,但我不确定我应该如何与它们交互。我应该将它们绑定到 MyForm 的 python init() 函数中的变量吗?

更新 3:我似乎已经很好地引用了这些组件(SEEM TO),但现在我注意到事件处理似乎已关闭。我已经包含了更多我正在使用的代码。请原谅线程逻辑等的任何潜在问题,因为我还没有解决这个问题并且可以自己解决。我似乎无法得到的是事件处理。一如既往,我非常感谢任何意见并提前致谢!

以下是对我有用的方法:

  1. 我制作了一个 Windows 表单项目(称为 FormProject),它看起来与您的屏幕截图中的完全一样。我调用了输入文本框input_box、按钮input_button和状态文本框output_box。这些控件中的每一个都是完全被动的(在 C# 中没有订阅事件)。

  2. 我通过在“设计”视图中转到它们的每个属性并选择 Modifiers = Public 来制作所有这些控件 public (默认值为 Private)。 确保您的表单的 class 也是 public。

  3. 我将项目构建为 DLL,正如您已经知道的那样。

  4. 我编写了以下 IronPython 代码:(我将此代码放在与 FormProject 项目相同的解决方案中的单独项目中,但我确信无论您已经拥有的任何设置都可以正常工作)


记住你的CustomForm就是我的FormProject

import clr
import sys

clr.AddReference('System.Windows.Forms')
clr.AddReferenceToFileAndPath('C:/Full/Path/To/Compiled/FormProject.dll')

from System.Windows.Forms import *
from FormProject import *

class MyForm(Form1):
    def __init__(self):
        super(MyForm, self).__init__()
        self.input_button.Click += self.input_button_Click

    def input_button_Click(self, sender, e):
        self.output_box.Text += "Status: Tried to sign in with Name: \"" + self.input_box.Text + "\"\r\n"


Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault(False)

form = MyForm()
Application.Run(form)

我不确定为什么在您的 MyForm 构造函数中您尝试调用 self.InitializeComponent(),因为 (1) Form1.InitializeComponent() 是私有的,因此派生的 classes,并且 (2) 调用 super(MyForm, self).__init__() 已经通过 Form1 的构造函数,它调用 Form1.InitializeComponent。所以在我的代码中我只是把它拿出来了(我的代码工作得很好)。

如果你运行这个Python代码,点击按钮应该向输出框添加文本(根据输入框的文本),证明我写了一个事件处理程序和将其订阅到控件的事件,全部在 Python.

希望对您有所帮助!