引言
在之前的一片文章tkinter使用wpf控件_Smart-Space的博客-CSDN博客中,我们实现了将wpf框架嵌入tkinter中。但是众所周知?,wpf可以通过xaml编写界面,这样能够极大地减少代码编写量,提高效率。
但是,C#的xaml与cs结合是通过编译器实现的,而Python使用 .Net 只能够通过代码实现。不过,曲线救国的方法倒是一大堆。
能够导入xaml的控件
在wpf中,能够导入xaml的有:
-
Window
-
Frame
-
ContentControl及其父类和子类
这些控件,都可以通过设置content
属性,确定xaml内容。其中,Frame是通过Navigate
方法实现页面跳转。
介于Frame能够切换页面,因此我们选择Frame作为容器控件。
xaml
我们用如下xaml作为示例:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page1">
<StackPanel Name="LayoutRoot">
<Button Name="btn1"
BorderBrush="Black" BorderThickness="1"
ClickMode="Hover">
ClickMe1
</Button>
<Calendar Margin="20"
SelectedDate="2/15/2009"
DisplayDate="3/15/2009"
DisplayDateStart="1/10/2009"
DisplayDateEnd="4/18/2029"/>
<TreeView>
<TreeViewItem Header="Employee1">
<TreeViewItem Header="Jesper"/>
<TreeViewItem Header="Aaberg"/>
<TreeViewItem Header="12345"/>
</TreeViewItem>
<TreeViewItem Header="Employee2">
<TreeViewItem Header="Dominik"/>
<TreeViewItem Header="Paiha"/>
<TreeViewItem Header="98765"/>
</TreeViewItem>
</TreeView>
<RichTextBox Name="richTB">
<FlowDocument>
<Paragraph>
<Run>Paragraph 1</Run>
</Paragraph>
<Paragraph>
<Run>Paragraph 2</Run>
</Paragraph>
<Paragraph>
<Run>Paragraph 3</Run>
</Paragraph>
</FlowDocument>
</RichTextBox>
</StackPanel>
</Page>
解析xaml
作为 .Net 的一部分,wpf所要求的xaml读取结果当然不是Python自带的xml解析库的返回结果,而是基于System.Windows.Markup
的XamlReader
的解析结果。
from System.Windows.Markup import XamlReader
page = XamlReader.Parse(xaml)
注意,xaml解析需要在STA线程中执行。
导入Frame
这里直接使用Frame的Navigate
就可以了。
form.Navigate(page)
完整代码
import clr
clr.AddReference('System.Windows.Forms')
clr.AddReference("PresentationFramework.Classic, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")
clr.AddReference("PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")
clr.AddReference('WindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35')#?
clr.AddReference('System.Threading')
from clr import System
from System import Uri
from System.Windows.Markup import XamlReader
from System.Windows import LogicalTreeHelper
from System.Windows.Controls import Frame as wpfFrame,Button as wpfButton
from System.Windows.Forms.Integration import ElementHost
from System.Windows.Forms import Control
from System.Threading import Thread,ApartmentState,ThreadStart
from tkinter import Frame,Tk
from tkinter import ttk
import ctypes
user32=ctypes.windll.user32
from tkwpf import tkWPF
xaml='''
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page1">
<StackPanel Name="LayoutRoot">
<Button Name="btn1"
BorderBrush="Black" BorderThickness="1"
ClickMode="Hover">
ClickMe1
</Button>
<Calendar Margin="20"
SelectedDate="2/15/2009"
DisplayDate="3/15/2009"
DisplayDateStart="1/10/2009"
DisplayDateEnd="4/18/2029"/>
<TreeView>
<TreeViewItem Header="Employee1">
<TreeViewItem Header="Jesper"/>
<TreeViewItem Header="Aaberg"/>
<TreeViewItem Header="12345"/>
</TreeViewItem>
<TreeViewItem Header="Employee2">
<TreeViewItem Header="Dominik"/>
<TreeViewItem Header="Paiha"/>
<TreeViewItem Header="98765"/>
</TreeViewItem>
</TreeView>
<RichTextBox Name="richTB">
<FlowDocument>
<Paragraph>
<Run>Paragraph 1</Run>
</Paragraph>
<Paragraph>
<Run>Paragraph 2</Run>
</Paragraph>
<Paragraph>
<Run>Paragraph 3</Run>
</Paragraph>
</FlowDocument>
</RichTextBox>
</StackPanel>
</Page>
'''
def STAMain():
global media
try:
a=Tk()
a.geometry('500x500')
f=tkWPF(a)
f.pack(fill='both',expand=True)
form=wpfFrame()
page = XamlReader.Parse(xaml)
form.Navigate(page)
f.control(form)
Button1 = LogicalTreeHelper.FindLogicalNode(page, "btn1")
print(Button1)
a.mainloop()
except Exception as err:
print(err)
def main():
t = Thread(ThreadStart(STAMain))
t.ApartmentState = ApartmentState.STA
t.Start()
t.Join()
if __name__ == "__main__":
main()
效果:
结语
因为一些原因,我没有将其写成类,只是做了一个范例而已。有需要的可以自行更改源码。
🔆tkinter创新🔆