代码中吸取营养:GoodTechnique

📅 2026/7/21 19:13:30
代码中吸取营养:GoodTechnique
package com.Murphy;/*这个程序的作用是捕获各个区域的鼠标坐标/// GoodTechnique.java// Your first choice when overriding components// should be to install listeners. The code is// much safer, more modular and maintainable.import java.awt.;import java.awt.event.*;class Display {public static final int //定义消息类型EVENT 0, COMPONENT 1,MOUSE 2, MOUSE_MOVE 3,FOCUS 4, KEY 5, ACTION 6,LAST 7;public String[] evnt; //事件的本质其实就是一个String这里定义的是事件组,下标对应消息类型存放一组消息。Display() {evnt new String[LAST];for(int i 0; i LAST; i)evnt[i] new String();}//这里是精髓用一个方法输出7行信息对应每一种事件。public void show(Graphics g) {for(int i 0; i LAST; i)g.drawString(evnt[i], 0, 10 * i 10); //直接用画布输出字串}}//定义一个可以接收鼠标位置信息的panel类class EnabledPanel extends Panel {Color c;int id;Display display new Display(); //这里利用Display类在画布中显示事件信息。public EnabledPanel(int i, Color mc) { //用panel的ID和底色来初始化id i;c mc; //颜色放入成员变量setLayout(new BorderLayout());add(new MyButton(), BorderLayout.SOUTH);addComponentListener(new CL());addFocusListener(new FL());addKeyListener(new KL());addMouseListener(new ML());addMouseMotionListener(new MML());}// To eliminate flicker:Overridepublic void update(Graphics g) { //更新画布paint(g);}Overridepublic void paint(Graphics g) { //画布作图颜色宽高填充区域带事件字符串显示区域g.setColor©;Dimension s getSize();g.fillRect(0, 0, s.width, s.height);g.setColor(Color.black);display.show(g);}// Don’t need to enable anything for this:Overridepublic void processEvent(AWTEvent e) {display.evnt[Display.EVENT] e.toString();repaint();super.processEvent(e); //保持父类消息事件}//实现组件监听得到各种事件的消息串class CL implements ComponentListener {public void componentMoved(ComponentEvent e) {display.evnt[Display.COMPONENT] “Component moved”;repaint();}public void componentResized(ComponentEvent e) { display.evnt[Display.COMPONENT] Component resized; repaint(); } public void componentHidden(ComponentEvent e) { display.evnt[Display.COMPONENT] Component hidden; repaint(); } public void componentShown(ComponentEvent e) { display.evnt[Display.COMPONENT] Component shown; repaint(); } } class FL implements FocusListener { public void focusGained(FocusEvent e) { display.evnt[Display.FOCUS] FOCUS gained; repaint(); } public void focusLost(FocusEvent e) { display.evnt[Display.FOCUS] FOCUS lost; repaint(); } } //得到键盘消息键盘的消息值e 其实就是每个按键的ASCII码值的字符表示 class KL implements KeyListener { public void keyPressed(KeyEvent e) { display.evnt[Display.KEY] KEY pressed: ; showCode(e); } public void keyReleased (KeyEvent e){ display.evnt[Display.KEY] KEY released: ; showCode(e); } public void keyTyped (KeyEvent e){ display.evnt[Display.KEY] KEY typed: ; showCode(e); } void showCode (KeyEvent e){ int code e.getKeyCode(); display.evnt[Display.KEY] KeyEvent.getKeyText(code); repaint(); } } class ML implements MouseListener { public void mouseClicked(MouseEvent e) { requestFocus(); // Get FOCUS on click display.evnt[Display.MOUSE] MOUSE clicked; showMouse(e); } public void mousePressed(MouseEvent e) { display.evnt[Display.MOUSE] MOUSE pressed; showMouse(e); } public void mouseReleased(MouseEvent e) { display.evnt[Display.MOUSE] MOUSE released; showMouse(e); } public void mouseEntered(MouseEvent e) { display.evnt[Display.MOUSE] MOUSE entered; showMouse(e); } public void mouseExited(MouseEvent e) { display.evnt[Display.MOUSE] MOUSE exited; showMouse(e); } void showMouse(MouseEvent e) { display.evnt[Display.MOUSE] , x e.getX() , y e.getY(); repaint(); } } class MML implements MouseMotionListener { public void mouseDragged(MouseEvent e) { display.evnt[Display.MOUSE_MOVE] MOUSE dragged; showMouse(e); } public void mouseMoved(MouseEvent e) { display.evnt[Display.MOUSE_MOVE] MOUSE moved; showMouse(e); } //鼠标消息用画布字串输入记录当前的鼠标坐标鼠标消息对应的就是坐标可以用e.getX()和e.getY()得到 void showMouse(MouseEvent e) { display.evnt[Display.MOUSE_MOVE] , x e.getX() , y e.getY(); repaint(); } }}class MyButton extends Button {int clickCounter;String label “”;public MyButton() { addActionListener(new AL()); } public void paint(Graphics g) { //绿色按钮南北布局南黑色边框 g.setColor(Color.green); Dimension s getSize(); g.fillRect(0, 0, s.width, s.height); g.setColor(Color.black); g.drawRect(0, 0, s.width - 1, s.height - 1); drawLabel(g); } private void drawLabel(Graphics g) { FontMetrics fm g.getFontMetrics(); int width fm.stringWidth(label); int height fm.getHeight(); int ascent fm.getAscent(); //上坡度基线到字符顶的距离 int leading fm.getLeading(); //行间距 int horizMargin (getSize().width - width) / 2; //水平缩进 按钮宽度减去字符串宽度除以2这样基本居中 int verMargin (getSize().height - height) / 2; g.setColor(Color.red); g.drawString(label, horizMargin, //这个很经典要学会这些参数。 verMargin ascent leading); } class AL implements ActionListener { public void actionPerformed(ActionEvent e) { //这里可以把按钮上的点击次数记录显示出来。 clickCounter; label click # clickCounter e.toString(); repaint(); } }}public class GoodTechnique extends Frame {GoodTechnique() {//用表格模式增加3个记录事件带button的Panel,这样右下角会空出一个区域。setLayout(new GridLayout(2,2));add(new EnabledPanel(1, Color.cyan));add(new EnabledPanel(2, Color.lightGray));add(new EnabledPanel(3, Color.yellow));}public static void main(String[] args) {Frame f new GoodTechnique();f.setTitle(“Good Technique”);f.addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){System.out.println(e);System.out.println(“Window Closing”);System.exit(0);}});f.setSize(700,700);f.setVisible(true);}}学会用Graphics类的对象方法drawString输出文本参数列表(strText, horizMargin, verMarginascentleading)其中horizMargin和verMargin可以通过FontMetrics的高度宽度算出。 而ascent和leading来自FontMetrics的方法graphics.getFontMetrics.getAscent 或者getLeading.在键盘按键事件中可以得到按键ASCII码值 KeyEvent e; code e.getKeyCode();而ASCII码值可以用KeyEvent类方法转为文本显示: KeyEvent.getKeyText(code); 注意这里控制字符也能显示出来。在鼠标按键的事件中可以得到鼠标的当前坐标: MouseEvent e ; e.getX()和e.getY();这个坐标返回的是当前监听者的相对坐标。 可能需要requestFocus()这个属于Component对象方法监听者都自带。画布要想生效的话记得在其所在组件中使用update(Graphics g)重写内容添加paint(g)画刷方法paint(Graphics g)也需要重写里面需要包含诸如drawString方法才能让新画布内容生效。还需要重写过程事件processEvent(AWTEvent e) 里面增加repaint(); super.processEvent(e);虚拟键小程序package UsePaint;import java.awt.*;import java.awt.event.KeyAdapter;import java.awt.event.KeyEvent;public class VirtualKeyTest {public static void main(String[] args) {new KeyFrame();}}class KeyFrame extends Frame{public KeyFrame(){setBounds(200,200,800,600);setVisible(true);this.addKeyListener(new KeyAdapter() {Overridepublic void keyPressed(KeyEvent e) {//super.keyPressed(e);int keycode e.getKeyCode();if (keycodeKeyEvent.VK_UP){ //直接VK_UP–Goto就可以看到所有键值System.out.println(“你按了上键”);}else{//这里显示的是10进制值除了Tab键其他所有键都有键值//这种虚拟键并不支持组合键或切换键如NumLockSystem.out.println(keycode);}}});}}10. 用反射机制追溯控件源头我们可以用getSuperclass来追踪每一个组件的父类源头下面是Frame 的类源头。class java.awt.Frameclass java.awt.Windowclass java.awt.Containerclass java.awt.Componentclass java.lang.Objectnull //Object 的父类是NULL如果用变量引用了Null再继续getSupercass则会 NullPointerException.Button–Component–Object–nullCanvas–Component–Object–nullCheckbox–Component–Object–nullCheckboxMenuItem–MenuItem–MenuComponent–Object–nullChoice–Component–Object–nullDialog–Window–Container–Component–Object–nullFileDialog-Dialog–Window–Container–Component–Object–nullLabel–Component–Object–nullList–Component–Object–nullMenu–MenuItem–MenuComponent–Object–nullMenuItem–MenuComponent–Object–nullPanel–Container–Component–Object–nullPopupMenu–Menu–MenuItem–MenuComponent–Object–nullScrollbar–Component–Object–nullScrollPane–Container–Component–Object–nullTextArea–TextComponent–Component–Object–nullTextField–TextComponent–Component–Object–nullString–Object–nullInteger–Number–Object–null所有的基础数据类型类都没有父类。而对应的方法类如Integer, Double,Float.都来自Number类。Boolean,String方法类除外它们是直接来自Object.所有数组的类也是来自Object.byte , short, int , long, float, double, char, boolean –null