Jython GUI开发:从基础到实践
1. Jython GUI开发概述
在Jython中开发图形用户界面(GUI),主要的工具包是Java的抽象窗口工具包(AWT)和Swing类。这是因为Jython用Java编写,能很好地在Python语法中使用Java类。不过,AWT和Swing并非实现GUI的唯一选择,也有越来越多与其他工具包的绑定可供使用,但这里主要关注用Jython编写的AWT和Swing GUI。
2. Java与Jython GUI对比
-
Java GUI示例
以下是一个简单的Java GUI代码示例:
// file SimpleJavaGUI.java
import java.awt.*;
import java.awt.event.*;
class SimpleJavaGUI implements ActionListener {
private Button mybutton = new Button("OK");
private Label mylabel = new Label("A Java GUI", Label.CENTER);
public SimpleJavaGUI() {
Frame top_frame = new Frame();
Panel panel = new Panel();
top_frame.setTitle("A Basic Jython GUI");
top_frame.setBackground(Color.yellow);
top_frame.addWindowListener(
new WindowAdapter() {
public void windowClosing(windowEvent e) {
System.exit(0);
}
});
mybutton.addActionListener(this);
panel.add(mylabel);
panel.add(mybutton);
top_frame.add(panel);
top_frame.pack();
Dimension winSz = Toolkit.getDefaultToolkit().getScreenSize();
top_frame.setLocation(winSz.width/2 - top__frame.getWidth()/2,
winSz.height/2 - top__frame.height()/2);
top_frame.setVisible(true);
}
public static void main(String[] args)) {
SimpleJavaGUI s = new SimpleJavaGUI();
}
public void actionPerformed(ActionEvent event) {
System.exit(0);
}
}
这个示例展示了如何使用AWT类、bean属性和bean事件来创建一个简单的GUI。
-
Jython GUI示例
对应的Jython代码如下:
# File: simpleJythonGUI.py
import java
from java import awt
# Make an exit function
def exit(e):
java.lang.System.exit(0)
#Make root frame and the panel it will contain
top_frame = awt.Frame(title="A Basic Jython GUI",
background = awt.Color.yellow,
windowClosing=exit)
panel = awt.Panel()
#Add stuff to look at inside frame
mylabel = awt.Label("A Jython GUI", awt.Label.CENTER)
mybutton = awt.Button("OK", actionPerformed=exit)
panel.add(mylabel)
panel.add(mybutton)
top_frame.add(panel)
# pack and show
top_frame.pack()
# set location
toolkit = awt.Toolkit.getDefaultToolkit()
winSz = toolkit.screenSize
top_frame.setLocation(winSz.width/2 - top__frame.size.width/2,
winSz.height/2 - top__frame.height/2)
top_frame.visible = 1
与Java代码相比,Jython代码在语法上有明显不同,例如不需要类型声明、访问修饰符、分号和大括号。同时,Jython通过自动添加bean属性和事件作为类属性,使用赋值来处理属性和事件,简化了代码。
3. Bean属性和事件
-
Bean属性
- 基本概念 :bean是遵循特定方法、属性和事件约定的类。bean的属性通过get和set方法操作,事件通过add和remove方法指定监听器对象。
-
Jython的处理方式
:Jython通过自动将bean属性和事件作为类属性,简化了操作。例如,Java中使用
bean.getName()获取属性,在Jython中可以直接使用bean.name;Java中使用bean.setName("new name")设置属性,在Jython中只需bean.name = "new name"。 -
属性类型和元组
:Jython会自动将分配给bean属性的元组解释为属性类型的构造函数。例如,将三元组分配给
background属性会自动成为java.awt.Color类的构造函数值,分配给bounds属性会自动成为Rectangle类型。
-
Bean事件
-
Java的处理方式
:在Java GUI中处理事件,需要添加实现事件监听器接口的类,并使用
addEvent Listener方法设置监听器。 -
Jython的处理方式
:Jython使用自动事件属性作为属性,允许将可调用对象分配给事件的bean名称。例如,实现
windowClosing事件,只需将可调用对象分配给容器的windowClosing属性。
-
Java的处理方式
:在Java GUI中处理事件,需要添加实现事件监听器接口的类,并使用
4. 名称优先级
Jython支持实例方法、类静态字段、bean属性和bean事件属性,可能会出现命名冲突。Jython通过分配优先级来解决冲突,优先级顺序如下:
1. 方法
2. 类静态属性
3. 事件属性
4. Bean属性
5. pawt包
Jython的pawt包为在Jython中使用AWT和Swing提供了一些便利模块,包括GridBag、colors、test和swing。
-
GridBag
-
功能
:
pawt.GridBag
类是一个包装类,用于简化
java.awt.GridBagLayout
和
java.awt.GridBagConstraints
的使用。
-
使用方法
:要使用
pawt.GridBag
类,需要将Java容器的实例提供给其构造函数。例如:
from java import awt
import pawt
top_frame = awt.Frame("GridBag frame")
bag = pawt.GridBag(top_frame)
- **示例代码**:以下是使用`pawt.GridBag`模块简化地址簿条目设置的示例:
from java import awt
from java.awt.event import ActionListener
from pawt import GridBag
from java.lang import System
frame = awt.Frame("GridBag Test", visible=1,size=(200,200),
windowClosing=lambda e: System.exit(0))
pane=awt.Panel(background=(200,200,255))
frame.add(pane)
bag = GridBag(pane, fill="HORIZONTAL")
labelFactory = lambda x: awt.Label(x, background=awt.Color.yellow)
title = awt.Label("Jython GridBag Address Book", awt.Label.CENTER)
bag.addRow(title)
category = awt.Choice()
map(category.add, ["Family", "Friends", "Business"])
bag.add(labelFactory("Category: "))
bag.addRow(category, anchor="WEST", fill="NONE")
name = awt.TextField(25)
bag.add(labelFactory("Name: "))
bag.addRow(name)
address = awt.TextField(35)
bag.add(labelFactory("Address: "))
bag.addRow(address)
city = awt.TextField(25)
bag.add(labelFactory("City: "))
bag.add(city)
state = awt.TextField(2)
bag.add(labelFactory("State: "))
bag.add(state)
zip = awt.TextField(5)
bag.add(labelFactory("zip: "))
bag.addRow(zip)
homephone_areacode = awt.TextField(3)
homephone_prefix = awt.TextField(3)
homephone_suffix = awt.TextField(4)
cellphone_areacode = awt.TextField(3)
cellphone_prefix = awt.TextField(3)
cellphone_suffix = awt.TextField(4)
frame.pack()
-
colors
-
功能
:
colors模块包含许多命名颜色,方便用户使用。可以通过dir(pawt.colors)查看所有定义的颜色。
-
功能
:
-
test
-
功能
:
test函数允许简单测试图形组件,无需使用Frame或Panel即可查看组件效果。例如:
-
功能
:
import java
import pawt
b = java.awt.Button("help", background=(212,144,100))
pawt.test(b)
-
pawt.swing
-
功能
:
pawt.swing模块选择适合JDK的Swing库,并提供特定于Swing组件的测试函数。 -
注意事项
:该模块是一个动态模块,在编译Jython时可能会出现问题。因此,在子类化Swing组件或编译Jython应用程序时,最好直接使用
javax.swing。
-
功能
:
6. 示例
-
简单AWT图形
以下是一个简单的Jython横幅示例:
# file: jythonBanner.py
from java import awt
import java
class Banner(awt.Canvas):
def paint(self, g):
g.color = 204, 204, 204
g.fillRect(15, 15, self.width-30, self.height-30)
g.color = 102, 102, 153
g.font = "Helvetica Bold", awt.Font.BOLD, 28
message = ">>> Jython"
g.drawString(message,
self.width/2 - len(message)*10, #approx. center
self.height/2 + 14) #same here
top_frame = awt.Frame("Jython Banner", size=(350, 150),
windowClosing=lambda e: java.lang.System.exit(0))
top_frame.add( Banner() )
top_frame.visible = 1
这个示例展示了如何使用Jython的自动bean属性和事件属性来创建一个简单的图形界面。
-
添加事件
以下是一个绘制极坐标图并处理鼠标事件的示例:
# file: PolarGraph.py
import java
from java.lang import System
from java import awt
from java.lang import Math
class Main(awt.Frame):
def __init__(self):
self.background=awt.Color.gray
self.bounds=(50,50,400,400)
self.windowClosing=lambda e: System.exit(0)
self.r = awt.Label("r: ")
self.theta = awt.Label("theta: ")
infoPanel = awt.Panel()
infoPanel.add(self.r)
infoPanel.add(self.theta)
self.graph = PolarCanvas()
self.add("North", infoPanel)
self.add("Center", self.graph)
self.visible = 1
self.graph.mouseMoved = self.updateCoords
def updateCoords(self, e):
limit = self.graph.limit
width = self.graph.width
height = self.graph.height
x = (2 * e.x * limit)/width - limit
y = limit - (2 * e.y * limit)/height
r = Math.sqrt(x**2 + y**2)
if x == 0:
theta = 0
else:
theta = Math.atan(Math.abs(y)/Math.abs(x))
if x < 0 and y > 0:
theta = Math.PI - theta
elif x < 0 and y <= 0:
theta = theta + Math.PI
elif x > 0 and y < 0:
theta = 2 * Math.PI - theta
self.r.text = "r: %0.2f" % r
self.theta.text = "theta: %0.2f" % theta
class PolarCanvas(awt.Canvas):
def __init__(self, interval=100, limit=400):
self.background=awt.Color.white
self.mouseReleased=self.onClick
self.interval = interval
self.limit = limit
self.points = []
def onClick(self, e):
x = (2 * e.x * self.limit)/self.width - self.limit
y = self.limit - (2 * e.y * self.limit)/self.height
self.points.append(awt.Point(x, y))
self.repaint()
def paint(self, g):
rings = self.limit/self.interval
step = (self.width/(rings*2), self.height/(rings*2))
# Draw rings
for x in range(1, rings + 1):
r = awt.Rectangle(x*step[0], x*step[1],
step[0] **(rings-x)*2,
step[1]*(rings-x)*2)
lambda x, y: max(y - x ** 20, 10)
g.color = (max(140-x*20,10), max(200-x*20,10),
max(240-x*20,10))
g.fillOval(r.x, r.y, r.width, r.height)
g.color = awt.Color.black
g.drawOval(r.x, r.y, r.width, r.height)
g.drawString(str((rings*self.interval)-(x*self.interval)),
r.x - 8, self.height/2 + 12)
# draw center dot
g.fillOval(self.width/2-2, self.height/2-2, 4, 4)
# draw points
g.color = awt.Color.red
for p in self.points:
x = (p.x * self.width)/(2 * self.limit) + self.width/2
y = self.height/2 - (p.y * self.height)/(2 * self.limit)
g.fillOval(x, y, 4, 4)
if __name__ == '__main__':
app = Main()
这个示例展示了如何使用Jython的自动事件属性来处理鼠标事件。
-
图像显示
以下是一个显示图像的示例:
# file jyimage.py
from java.lang import System
from java import awt
class jyimage(awt.Frame):
def __init__(self, im):
self.im = awt.Toolkit.getDefaultToolkit().getImage(im)
self.bounds=100,100,200,200
self.title="Jython Image Display"
self.windowClosing=lambda e: System.exit(0)
mt = awt.MediaTracker(self)
mt.addImage(self.im, 0)
mt.waitForID(0)
self.addNotify() # add peer to get insets
i = self.insets
self.resize(self.im.width + i.left + i.right,
self.im.height + i.top + i.bottom)
def paint(self, g):
g.drawImage(self.im, self.insets.left, self.insets.top, self)
if __name__ == '__main__':
f = jyimage("jython-new-small.gif")
f.visible = 1
这个示例展示了如何使用Jython显示图像,并处理图像加载和显示的细节。
-
菜单和菜单事件
以下是一个创建菜单并处理菜单事件的示例:
# file: jythonmenus.py
from java import awt
from java.awt import event
from java.lang import System
menus = [
('File', ['New', 'Open', 'Save', 'Saveas', 'Close']),
('Edit', ['Copy', 'Cut', 'Paste']),
]
class MenuTest(awt.Frame):
def __init__(self):
bar = awt.MenuBar()
for menu, menuitems in menus:
menu = awt.Menu(menu)
for menuitem in menuitems:
method = getattr(self, 'on%s' % menuitem)
item = awt.MenuItem(menuitem, actionPerformed=method)
menu.add(item)
bar.add(menu)
self.menuBar = bar
self.windowClosing = lambda e: System.exit(0)
self.eventLabel = awt.Label("Event: ")
self.bounds = 100, 100, 200, 100
self.add(self.eventLabel)
def onNew(self, e):
self.eventLabel.text = "Event: onNew"
def onOpen(self, e):
self.eventLabel.text = "Event: onOpen"
def onSave(self, e):
self.eventLabel.text = "Event: onSave"
def onSaveas(self, e):
self.eventLabel.text = "Event: onSaveas"
def onClose(self, e):
self.eventLabel.text = "Event: onClose"
System.exit(0)
def onCopy(self, e):
self.eventLabel.text = "Event: onCopy"
def onCut(self, e):
self.eventLabel.text = "Event: onCut"
def onPaste(self, e):
self.eventLabel.text = "Event: onPaste"
f = MenuTest()
f.visible = 1
这个示例展示了如何使用Jython创建菜单并处理菜单事件。
-
拖放功能
以下是一个实现拖放功能的示例:
# file: ListDnD.py
from java import awt
from java.awt import dnd
from java.lang import System
from java.awt import datatransfer
class JythonDnD(awt.Frame, dnd.DragSourceListener, dnd.DragGestureListener):
def __init__(self):
self.title="Jython Drag -n- Drop Implementation"
self.bounds = 100, 100, 300, 200
self.windowClosing = lambda e: System.exit(0)
self.draglist = awt.List()
map(self.draglist.add, ["1","2","3","4","5"])
self.droplist = droplist([])
self.dropTarget = dnd.DropTarget(self,
dnd.DnDConstants.ACTION_COPY_OR_MOVE, self.droplist)
self.layout = awt.GridLayout(1, 2, 2, 2)
self.add(self.draglist)
self.add(self.droplist)
self.dragSource = dnd.DragSource()
self.recognize = self.dragSource.createDefaultDragGestureRecognizer(
self.draglist,
dnd.DnDConstants.ACTION_COPY_OR_MOVE,
self)
def dragGestureRecognized(self, e):
item = self.draglist.getSelectedItem()
e.startDrag(self.dragSource.DefaultCopyDrop,
datatransfer.StringSelection(item), self)
def dragEnter(self, e): pass
def dragOver(self, e): pass
def dragExit(self, e): pass
def dragDropEnd(self, e): pass
def dropActionChanged(self, e): pass
class droplist(awt.List, dnd.DropTargetListener):
def __init__(self, datalist):
map(self.add, datalist)
self.dropTarget = dnd.DropTarget(self, 3, self)
def drop(self, e):
transfer = e.getTransferable()
data = transfer.getTransferData(datatransfer.DataFlavor.stringFlavor)
self.add(data)
e.dropComplete(1)
def dragEnter(self, e):
e.acceptDrag(dnd.DnDConstants.ACTION_COPY_OR_MOVE)
def dragExit(self, e): pass
def dragOver(self, e): pass
def dropActionChanged(self, e): pass
win = JythonDnD()
win.visible=1
这个示例展示了如何使用Jython实现拖放功能。
-
Swing示例
以下是一个简单的Swing树显示示例:
# file: SwingTree.py
from javax import swing
from javax.swing import tree
import sys
top_frame = swing.JFrame("A Simple Tree in Jython and Swing",
windowClosing=lambda e: sys.exit(0),
background=(180,180,200),
)
data = tree.DefaultMutableTreeNode("Root")
data.add(tree.DefaultMutableTreeNode("a leaf"))
childNode = tree.DefaultMutableTreeNode("a node")
childNode.add(tree.DefaultMutableTreeNode("another leaf"))
data.add(childNode)
t = swing.JTree(data)
t.putClientProperty("JTree.lineStyle", "Angled")
top_frame.contentPane.add(t)
top_frame.bounds = 100, 100, 200, 200
top_frame.visible = 1
这个示例展示了如何使用Jython创建Swing应用程序。
总结
通过以上示例可以看出,Jython在GUI开发中具有很多优势,如简化代码、自动处理bean属性和事件等。同时,pawt包提供的便利模块也进一步提高了开发效率。无论是使用AWT还是Swing,Jython都能帮助开发者更轻松地创建图形用户界面。
流程图
graph TD;
A[开始] --> B[Jython GUI开发];
B --> C[对比Java和Jython GUI];
B --> D[Bean属性和事件];
B --> E[pawt包];
B --> F[示例];
C --> C1[Java GUI示例];
C --> C2[Jython GUI示例];
D --> D1[Bean属性];
D --> D2[Bean事件];
D --> D3[名称优先级];
E --> E1[GridBag];
E --> E2[colors];
E --> E3[test];
E --> E4[pawt.swing];
F --> F1[简单AWT图形];
F --> F2[添加事件];
F --> F3[图像显示];
F --> F4[菜单和菜单事件];
F --> F5[拖放功能];
F --> F6[Swing示例];
表格
| 模块 | 功能 |
|---|---|
| GridBag |
简化
java.awt.GridBagLayout
和
java.awt.GridBagConstraints
的使用
|
| colors | 包含许多命名颜色,方便使用 |
| test | 允许简单测试图形组件 |
| pawt.swing | 选择适合JDK的Swing库,并提供特定于Swing组件的测试函数 |
Jython GUI开发:从基础到实践
7. 深入理解Jython GUI开发的技术细节
-
自动类型转换
在Jython中,存在自动类型转换机制。例如,setVisible方法需要Java的Boolean参数,Jython会将PyInteger类型的1转换为Boolean类型的true,0转换为false。这意味着在Jython中可以将visible属性设置为1来显示组件,如top_frame.visible = 1。 -
类的使用
在Jython中,类不是必需的。虽然使用类可以更准确地翻译Java代码,但Jython允许不使用类来实现GUI。如SimpleJythonGUI示例中就没有使用类,但实现了与Java版本几乎相同的GUI。不过,由于AWT和Swing类的特性,复杂的无类GUI实现起来较为困难。
8. 不同场景下的Jython GUI开发技巧
-
快速原型开发
由于Jython可以轻松将Java GUI代码转换为Jython代码,因此在进行GUI原型开发时,使用Jython可以快速验证想法。开发人员可以先在Jython中进行原型设计,之后再根据需要将其转换为Java代码。例如,在开发一个简单的表单界面时,可以先使用Jython快速搭建界面,测试功能的可行性。 -
与Java生态的集成
Jython本身是基于Java的,能够很好地与Java生态集成。在开发GUI时,可以利用Java丰富的类库和资源。例如,在处理复杂的业务逻辑时,可以调用Java的类和方法。同时,Jython的自动bean属性和事件属性也能与Java的AWT和Swing类无缝配合。
9. 常见问题及解决方案
-
命名冲突问题
如前文所述,Jython支持多种属性类型,可能会出现命名冲突。当遇到命名冲突时,需要根据名称优先级来解决。例如,如果一个方法名与bean属性名冲突,Jython会优先使用方法。开发人员在编写代码时,应尽量避免命名冲突,或者在出现冲突时,根据优先级规则进行调整。 -
pawt.swing模块的使用问题
pawt.swing模块是一个动态模块,在编译Jython时可能会出现问题。如果需要对Jython应用程序进行编译,或者子类化Swing组件,建议直接使用javax.swing,避免使用pawt.swing模块。
10. 未来发展趋势
-
更多工具包的支持
随着技术的发展,可能会有更多与其他工具包的绑定出现,使得Jython在GUI开发中有更多的选择。这将进一步丰富Jython的应用场景,提高开发的灵活性。 -
性能优化
未来可能会对Jython的性能进行优化,特别是在处理大规模GUI应用时,提高响应速度和资源利用率。这将使得Jython在更复杂的项目中也能有出色的表现。
11. 总结与展望
Jython在GUI开发中展现出了独特的优势,通过简化代码、自动处理bean属性和事件等功能,大大提高了开发效率。pawt包的出现,更是为开发提供了便利。无论是初学者还是有经验的开发者,都能利用Jython快速创建出功能丰富的图形用户界面。
在未来的开发中,我们可以期待Jython在GUI领域有更多的创新和发展。同时,开发者也可以不断探索Jython的更多可能性,将其应用到更广泛的项目中。
流程图
graph TD;
A[Jython GUI开发] --> B[技术细节];
A --> C[开发技巧];
A --> D[常见问题];
A --> E[未来趋势];
B --> B1[自动类型转换];
B --> B2[类的使用];
C --> C1[快速原型开发];
C --> C2[与Java生态集成];
D --> D1[命名冲突问题];
D --> D2[pawt.swing模块问题];
E --> E1[更多工具包支持];
E --> E2[性能优化];
表格
| 问题 | 解决方案 |
|---|---|
| 命名冲突 | 根据名称优先级(方法 > 类静态属性 > 事件属性 > Bean属性)解决 |
| pawt.swing模块编译问题 |
子类化Swing组件或编译Jython应用时,直接使用
javax.swing
|
超级会员免费看
26

被折叠的 条评论
为什么被折叠?



