一,MFC消息处理机制
WINDOWS 消息的种类:
1、标准WINDOWS消息:这类消息是以WM_为前缀,不过WM_COMMAND例外。 例如: WM_MOVE、WM_QUIT等。
2、命令消息:命令消息以WM_COMMAND为消息名。在消息中含有命令的标志符ID,以区分具体的命令。由菜单,工具栏等命令接口对象产生。
3、控件通知消息:控件通知消息也是以WM_COMMAND为消息名。由编辑框、列表框和子窗口发送给父窗口的通知消息。在消息中包含控件通知码,以区分具体控件的通知消息。
MFC中处理消息的顺序
1. AfxWndProc()接收消息,寻找消息所属的CWnd对象,然后调用AfxCallWndProc( )。
2. AfxCallWndProc()存储消息(消息标识符和消息参数)供未来参考,然后调用WindowProc( )。
3. WindowProc()发送消息给OnWndMsg( ),如果消息未被处理,则发送给DefWindowproc( )。
4. OnWndMsg()首先按字节对消息进行排序,对于WM_COMMAND消息,调用OnCommand()消息响应函数;对于WM_NOTIFY消息调用OnNotify()消息响应函数。任何被遗漏的消息将是标准消息。OnWndMsg()函数搜索类的消息映像,以找到一个能处理任何窗口消息的处理函数。如果OnWndMsg()函数不能找到这样的处理函数的话,则把消息返回到WindowProc()函数,由它将消息发送给DefWindowProc()函数。
5. OnCommand()查看这是不是一个控件通知(lParam参数不为NULL),如果它是,OnCommand()函数会试图将消息映射到制造通知的控件;如果它不是一个控件通知,或者控件拒绝映射的消息,OnCommand()就会调用OnCmdMsg()函数。
6. OnNotify( )也试图将消息映射到制造通知的控件;如果映射不成功,OnNotify( )就调用相同的OnCmdMsg( )函数。
7. 根据接收消息的类,OnCmdMsg()函数将在一个称为命令传递(Command Routing)的过程中潜在的传递命令消息和控件通知。例如:如果拥有该窗口的类是一个框架类,则命令和控件通知消息也被传递到视图和文档类,并为该类寻找一个消息处理函数。
MFC中创建窗口的顺序
1. PreCreateWindow()是一个重载函数,在窗口被创建前,可以在该重载函数中改变创建参数(可以设置窗口风格等等)。
2. PreSubclassWindow()也是一个重载函数,允许首先子分类一个窗口OnGetMinMaxInfo()为消息响应函数,响应的是WM_GETMINMAXINFO消息,允许设置窗口的最大或者最小尺寸。
3. OnNcCreate()也是一个消息响应函数,响应WM_NCCREATE消息,发送消息以告诉窗口的客户区即将被创建。
4. OnNcCalcSize()也是消息响应函数,响应WM_NCCALCSIZE消息,作用是允许改变窗口客户区大小。
5. OnCreate()也是消息响应函数,响应WM_CREATE消息,发送消息告诉一个窗口已经被创建。
6. OnSize()也是消息响应函数,响应WM_SIZE消息,发送该消息以告诉该窗口大小已经发生变化。
7. OnMove()也是消息响应函数,响应WM_MOVE消息,发送此消息说明窗口在移动。
8. OnChildNotify()为重载函数,作为部分消息映射被调用,告诉父窗口即将被告知一个窗口刚刚被创建。
SetTimer与WM_TIMER消息
Timer被设置后会一直存在,直到用KillTimer(hwnd, ID)删除。
Timer被创建后,每隔一定时间会发送 WM_TIMER 消息,当收到WM_TIMER 消息后,程序就会调用函数。也可以在创建Timer时指定回调函数。
SetTimer 原形如下,注意 CWnd 类的 SetTimer 方法没有第一个参数:
UINT_PTR SetTimer( HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc);
四个参数分别是: hWnd 所属的窗口句柄,如果 lpTimerFunc 为空,这个窗口将接收 WM_TIMER 消息。
nIDEvent 计时器ID值,发送 WM_TIMER消息时会附带发送这个值。
uElapse 超时时间。每uElapse毫秒发送WM_TIMER
lpTimerFunc 回调函数,如果为空,将发送 WM_TIMER 消息给 hWnd 指定的窗口的消息队列。
lpTimerFunc 的函数原型如下:
VOID CALLBACK TimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
用一个Windows窗口实例来解释消息处理
#include <windows.h>
#include <cstdio>
//回调函数
LRESULT CALLBACK WinSunProc(
HWND hwnd, // 窗口句柄
UINT message, // 消息代码
WPARAM wParam, // 附加参数
LPARAM lParam
) {
switch(message) {
case WM_CREATE: {
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
char str[20];
wsprintf(str, "窗口创建消息");
MessageBox(hwnd, str, "提示", MB_OK);
break;
}
case WM_PAINT: {
SetTimer(hwnd, 10, 100, NULL);
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
char str[20];
wsprintf(str, "Hello World");
TextOut(hdc, rand()%600, rand()%300, str, strlen(str));
break;
}
case WM_CHAR:
char szChar[20];
sprintf(szChar, "char code is %d", wParam);
MessageBox(hwnd, szChar, "您的按键", 0);
break;
case WM_TIMER:
InvalidateRect(hwnd, NULL, true);
break;
case WM_DESTROY: //销毁窗口
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // command line
int nCmdShow // show state
) {
// 窗口类
WNDCLASS wndcls;
wndcls.cbClsExtra = 0; // 类附加内存
wndcls.cbWndExtra = 0; // 窗口附加内存
wndcls.hbrBackground = (HBRUSH) GetStockObject(COLOR_WINDOW); // 背景画刷句柄
wndcls.hCursor = LoadCursor(NULL, IDC_ARROW); // 窗口光标句柄
wndcls.hIcon = LoadIcon(NULL, IDI_APPLICATION); // 窗口图标句柄
wndcls.hInstance = hInstance; // 包含窗口过程函数的程序实例
wndcls.lpfnWndProc = WinSunProc; // 只想窗口过程函数的指针
wndcls.lpszClassName = "CRoot"; // 窗口类名称
wndcls.lpszMenuName = NULL; // 菜单资源
wndcls.style = CS_HREDRAW | CS_VREDRAW; // 窗口样式
RegisterClass(&wndcls);
// 创建窗口, 定义一个变量用来保存成功创建窗口后返回的句柄
HWND hwnd = CreateWindow( // 窗口创建成功时返回为窗口分配的句柄 失败时返回NULL
"CRoot", // 窗口类名
"Hello World", // 窗口名字
WS_CAPTION|WS_SYSMENU, // 窗口样式
300, 300, // 窗口左上角坐标
700, 400, // 窗口宽高
NULL, // 父窗口句柄
NULL, // 窗口菜单句柄
hInstance, // 窗口所属应用程序实例
NULL // WM_CREATE消息附加参数lParam传入的数据指针
);
// 显示及刷新窗口
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
// 定义消息结构体
MSG msg;
while (GetMessage( // WM_QUIT消息返回0 错误返回-1
&msg, // 指向消息的结构体
NULL, // 指定接收属于哪一窗口的消息 通常设为NULL,用来接收属于调用线程的所有窗口的窗口消息
0, // 获取消息的最小值 通常为0
0)) // 获取消息的最大值 都设为0表示接收所有消息
{
TranslateMessage(&msg); // 将虚拟消息转换为字符消息 投递到调用线程的消息队列中 下次调用GetMessage时被取出
DispatchMessage(&msg); // 将消息传递给操作系统 由操作系统调用窗口过程函数对消息进行处理
}
return msg.wParam;
}
附加参数WPARAM与WM_COMMAND
创建一个按钮
CreateWindowEx(0,"Button","我是按钮",WS_VISIBLE|WS_CHILD,100,100,100,50,hwnd,(HMENU)10,0,0);
HMENU为按钮的ID号,监听器识别ID执行。
消息的附加信息在wParam中。
switch(message) {
case WM_CREATE: {
CreateWindowEx(0,"Button","我是按钮",WS_VISIBLE|WS_CHILD,100,100,100,50,hwnd,(HMENU)10,0,0);
break;
}
case WM_COMMAND: {
WORD wmId = LOWORD(wParam);
switch (wmId) {
case (10):
MessageBoxA(NULL,"Hello Button!","My TestProject",MB_OK);
break;
}
break;
}
实例(数据结构课程设计)
MFC界面的贪吃蛇游戏
#include <iostream>
#include <windows.h>
#include <ctime>
#include <fstream>
#include <cstring>
#include <string>
#include <algorithm>
#include "resource.h"
using namespace std;
#define IDT_TIMER 100
#define HEIGHT 300
#define WIDTH 500
int POINT_X[2], POINT_Y[2];
int score = 0;
int rate = 100;
int change = 0;
struct People {
char name[20];
int num;
bool operator < (const People &tmp) const {
return num > tmp.num;
}
} people[10];
int tot;
char user[20];
struct point {
int x, y;
};
struct Node {
point data;
Node *next;
} top;
struct Link {
Node *head, *last, *pre_last;
Link() {
last = head = ⊤
last->next = NULL;
last->data.x = 5;
last->data.y = 5;
}
} snake;
char direction = 'r';
void AddList() {
Node *tmp = new Node;
tmp->data.x = 1000;
tmp->data.y = 1000;
tmp->next = NULL;
snake.pre_last = snake.last;
snake.pre_last->next = tmp;
snake.last = tmp;
}
void GoAhead(int dx, int dy) {
snake.pre_last->next = NULL;
snake.last->data.x = snake.head->data.x + dx;
snake.last->data.y = snake.head->data.y + dy;
snake.last->next = snake.head;
snake.head = snake.last;
snake.last = snake.pre_last;
snake.pre_last = snake.head;
while (snake.pre_last->next != snake.last)
snake.pre_last = snake.pre_last->next;
}
void Drow(HWND hwnd) {
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
RECT rc;
//计分和静态文档
char sz[20];
wsprintf(sz, "分数:");
TextOut(hdc, WIDTH + 20, 40, sz, strlen(sz));
wsprintf(sz, "%d", score * 100);
TextOut(hdc, WIDTH + 20, 70, sz, strlen(sz));
wsprintf(sz, "排行榜:");
TextOut(hdc, WIDTH + 20, 90, sz, strlen(sz));
for(int i = 0; i<tot; i++) {
wsprintf(sz, "%s %d", people[i].name, people[i].num);
TextOut(hdc, WIDTH + 20, 110 + i * 20, sz, strlen(sz));
}
//画蛇
HBRUSH hBrush = CreateSolidBrush(RGB(0,0,0));
Node *tp = snake.head;
while (tp) {
rc.left = (tp->data.x) * 11;
rc.right = rc.left + 10;
rc.top = (tp->data.y) * 11;
rc.bottom = rc.top + 10;
FillRect(hdc, &rc, hBrush);
tp = tp->next;
}
//画点1
hBrush = CreateSolidBrush(RGB(255,0,0));
rc.left = POINT_X[0] * 11;
rc.right = rc.left + 10;
rc.top = POINT_Y[0] * 11;
rc.bottom = rc.top + 10;
FillRect(hdc, &rc, hBrush);
//画点2
rc.left = POINT_X[1] * 11;
rc.right = rc.left + 10;
rc.top = POINT_Y[1] * 11;
rc.bottom = rc.top + 10;
FillRect(hdc, &rc, hBrush);
//画边界
MoveToEx(hdc, WIDTH + 15, HEIGHT + 15, NULL);
LineTo(hdc, WIDTH + 15, 0);
DeleteObject(hBrush);
EndPaint(hwnd, &ps);
}
int getPoint() {
if (POINT_X[0] == (snake.head->data.x) && POINT_Y[0] == (snake.head->data.y))
return 0;
if (POINT_X[1] == (snake.head->data.x) && POINT_Y[1] == (snake.head->data.y))
return 1;
return -1;
}
int check() {
if (snake.head->data.x
< 0||(snake.head->data.x)*11>WIDTH||snake.head->data.y < 0||(snake.head->data.y)*11>HEIGHT)
return 1;
for (Node *p = snake.head->next; p->next; p = p->next)
if (p->data.x == snake.head->data.x && p->data.y == snake.head->data.y)
return 2;
return 0;
}
bool isOK(int x, int y) {
Node *tp = snake.head;
while (tp) {
if(tp->data.x == x && tp->data.y == y)
return 1;
tp = tp->next;
}
return 0;
}
//回调函数
LRESULT CALLBACK FUNC(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_CREATE: {
tot = 0;
ifstream inFile("score_list.txt");
while (!inFile.eof()) {
inFile >> people[tot].name >> people[tot].num;
tot++;
}
SetTimer(hwnd, IDT_TIMER, rate, NULL);
ifstream in("user.txt");
in >> user;
for(int i = 0; i<5; i++)
AddList();
break;
}
case WM_PAINT: { //窗口客户区需要重画
srand((int)time(0));
Drow(hwnd);
change = getPoint();
if (change >= 0) {
AddList();
score++;
srand((int)time(0));
do {
POINT_X[change] = (rand() % WIDTH) / 11, POINT_Y[change] = (rand() % HEIGHT) / 11;
} while(isOK(POINT_X[change], POINT_Y[change]));
}
int k = check();
if (k) {
if(k == 2) {
KillTimer(hwnd, IDT_TIMER);
MessageBox(NULL, "YOU LOSE !", "message", MB_OK);
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
char str[20];
wsprintf(str, "YOU LOSE !");
TextOut(hdc, 400, 100, str, strlen(str));
strcpy(people[tot].name, user), people[tot].num = score * 100;
sort(people, people + tot + 1);
if(tot > 5) tot = 5;
ofstream inFile("score_list.txt");
for(int i = 0; i < tot; i++) {
inFile << people[i].name << " " << people[i].num;
}
return 0;
}
int dx = -1, dy = -1;
if(snake.head->data.x * 11 < WIDTH / 2)
dx = 1;
if(snake.head->data.y * 11 < HEIGHT / 2)
dy = 1;
if(direction == 'r')
GoAhead(0, dy), GoAhead(-1, 0), direction = 'l';
else if(direction == 'u')
GoAhead(dx, 0), GoAhead(0, 1), direction = 'd';
else if(direction == 'l')
GoAhead(0, dy), GoAhead(1, 0), direction = 'r';
else if(direction == 'd')
GoAhead(dx, 0), GoAhead(0, -1), direction = 'u';
//PostQuitMessage(0);
}
return 0;
}
case WM_TIMER:
if (direction == 'l')
GoAhead(-1, 0);
else if (direction == 'r')
GoAhead(1, 0);
else if (direction == 'u')
GoAhead(0, -1);
else if (direction == 'd')
GoAhead(0, 1);
InvalidateRect(hwnd, NULL, true);
break;
case WM_KEYDOWN: {
Node *tp = snake.head;
{
switch (LOWORD(wParam)) {
case VK_UP:
if (direction != 'd')
direction = 'u';
break;
case VK_DOWN:
if (direction != 'u')
direction = 'd';
break;
case VK_RIGHT:
if (direction != 'l')
direction = 'r';
break;
case VK_LEFT:
if (direction != 'r')
direction = 'l';
break;
}
InvalidateRect(hwnd, NULL, TRUE);
}
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEX wndclass;
// 用描述主窗口的参数填充WNDCLASSEX结构
wndclass.cbSize = sizeof(wndclass); // 结构的大小
wndclass.style = CS_HREDRAW | CS_VREDRAW; // 指定如果大小改变就重画
wndclass.lpfnWndProc = FUNC; // 窗口函数指针
wndclass.cbClsExtra = 0; // 没有额外的类内存
wndclass.cbWndExtra = 0; // 没有额外的窗口内存
wndclass.hInstance = hInstance; // 实例句柄
wndclass.hIcon = LoadIcon(hInstance, (LPCTSTR) IDI_ICON1); // 使用预定义图标
wndclass.hCursor = LoadCursor(NULL,
IDC_ARROW); // 使用预定义的光标
wndclass.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1); // 使用灰色背景画刷
wndclass.lpszMenuName = NULL; // 不指定菜单
wndclass.lpszClassName = "MainWClass"; // 窗口类的名称
wndclass.hIconSm = LoadIcon(hInstance, (LPCTSTR) IDI_ICON1); // 没有类的小图标
// 注册这个窗口类
RegisterClassEx(&wndclass);
// 创建主窗口
HWND hwnd = CreateWindowEx(0, // dwExStyle,扩展样式
"MainWClass", // lpClassName,类名
"贪吃蛇", // lpWindowName,标题
WS_OVERLAPPEDWINDOW & (~WS_SIZEBOX) & (~WS_MAXIMIZEBOX),// dwStyle,窗口风格
300, //CW_USEDEFAULT, // X,初始 X 坐标
300, //CW_USEDEFAULT, // Y,初始 Y 坐标
WIDTH + 150, //CW_USEDEFAULT, // nWidth,宽度
HEIGHT + 50, //CW_USEDEFAULT, // nHeight,高度
NULL, // hWndParent,父窗口句柄
NULL, // hMenu,菜单句柄
hInstance, // hlnstance,程序实例句柄
NULL); // lpParam,用户数据
if (!hwnd) {
MessageBox(NULL, "无法创建游戏窗口", "error", MB_OK);
return -1;
}
srand((int)time(0));
do {
POINT_X[0] = (rand() % WIDTH) / 11, POINT_Y[0] = (rand() % HEIGHT) / 11;
} while(isOK(POINT_X[0], POINT_Y[0]));
do {
POINT_X[1] = (rand() % WIDTH) / 11, POINT_Y[1] = (rand() % HEIGHT) / 11;
} while(isOK(POINT_X[1], POINT_Y[1]));
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
MSG msg;
while ( GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
//将消息发送到回调函数
DispatchMessage(&msg);
}
//当GetMessage返回0时程序结束
return msg.wParam;
}
二,JAVA GUI消息
toggle.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {}
}
对每一个控件设置事件。
或,implements ActionListener 实现ActionListener接口
public void actionPerformed(ActionEvent e) {
if (e.getSource() == btnCalc) {}
if (e.getSource() == btnCalc2) {}
}
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.*;
class NumberFrame extends JFrame implements ActionListener {
JTextField txtStart;
JTextField txtEnd;
JTextField txtFactor;
JTextArea txtRes;
JButton btnCalc, btnCalc2;
JPanel inputPanel;
JScrollPane resultPane;
JPanel panel;
NumberFrame(String title) {
super(title);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(400, 150);
setLocation(300, 200);
setVisible(true);
Container cp = getContentPane();
panel = new JPanel();
panel.setLayout(new BorderLayout());
JPanel lblPane = new JPanel();
lblPane.setLayout(new GridLayout(4, 1));
lblPane.add(new JLabel("From"));
lblPane.add(new JLabel("To"));
lblPane.add(new JLabel("Factor"));
lblPane.add(new JLabel());
JPanel txtPane = new JPanel();
txtPane.setLayout(new GridLayout(4, 1)); // 划分成4行1列
txtStart = new JTextField();
txtEnd = new JTextField();
txtFactor = new JTextField();
txtPane.add(txtStart);
txtPane.add(txtEnd);
txtPane.add(txtFactor);
btnCalc = new JButton("Calculate");
btnCalc.addActionListener(this);
txtPane.add(btnCalc);
inputPanel = new JPanel();
inputPanel.setLayout(new BorderLayout());
inputPanel.add(lblPane, BorderLayout.WEST);
inputPanel.add(txtPane, BorderLayout.CENTER);
panel.add(inputPanel, BorderLayout.WEST);
// result panel
txtRes = new JTextArea(10, 10);
txtRes.setLineWrap(true);
resultPane = new JScrollPane(txtRes);
panel.add(resultPane, BorderLayout.CENTER);
btnCalc2 = new JButton("clean");
btnCalc2.addActionListener(this);
panel.add(btnCalc2, BorderLayout.SOUTH);
cp.add(panel);
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == btnCalc) {
txtRes.setText(null);
try {
int m = Integer.parseInt(txtStart.getText().trim());
int n = Integer.parseInt(txtEnd.getText().trim());
int factor = Integer.parseInt(txtFactor.getText().trim());
for (int i = m; i <= n; ++i) {
if (i % factor == 0)
txtRes.append(String.valueOf(i) + " ");
}
} catch (NumberFormatException e1) {
e1.printStackTrace();
}
}
if (e.getSource() == btnCalc2) {
txtRes.setText(null);
}
}
}
class TestButtons extends JFrame {
JButton jButton = new JButton("JButton"); // 按钮
JToggleButton toggle = new JToggleButton("Toggle Button"); // 切换按钮
JCheckBox checkBox = new JCheckBox("Check Box"); // 复选按钮
JRadioButton radio1 = new JRadioButton("Radio Button 1"); // 单选按钮
JRadioButton radio2 = new JRadioButton("Radio Button 2");
JRadioButton radio3 = new JRadioButton("Radio Button 3");
JLabel label = new JLabel("Here is Status, look here."); // 不是按钮,是静态文本
public TestButtons() {
super("Test");
setVisible(true);
setLocation(750, 200);
setSize(200, 250);
setDefaultCloseOperation(EXIT_ON_CLOSE);
getContentPane().setLayout(new java.awt.FlowLayout());
// 为一般按钮添加动作监听器
jButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
label.setText("You clicked jButton");
}
});
// 为切换按钮添加动作监听器
toggle.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JToggleButton toggle = (JToggleButton) e.getSource();
if (toggle.isSelected()) {
label.setText("You selected Toggle Button");
} else {
label.setText("You deselected Toggle Button");
}
}
});
// 为复选按钮添加条目监听器
checkBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
JCheckBox cb = (JCheckBox) e.getSource();
label.setText("Selected Check Box is " + cb.isSelected());
}
});
// 将单选按钮添加到按钮组中,按钮组中只能选一个
ButtonGroup group = new ButtonGroup();
group.add(radio1);
group.add(radio2);
group.add(radio3);
// 生成一个新的动作监听器对象,备用
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent e) {
JRadioButton radio = (JRadioButton) e.getSource();
if (radio == radio1) {
label.setText("You selected Radio Button 1");
} else if (radio == radio2) {
label.setText("You selected Radio Button 2");
} else {
label.setText("You selected Radio Button 3");
}
}
};
// 为各单选按钮添加动作监听器
radio1.addActionListener(al);
radio2.addActionListener(al);
radio3.addActionListener(al);
getContentPane().add(jButton);
getContentPane().add(toggle);
getContentPane().add(checkBox);
getContentPane().add(radio1);
getContentPane().add(radio2);
getContentPane().add(radio3);
getContentPane().add(label);
}
}
public class UI {
public static void main(String[] args) {
new NumberFrame("Number Game");
new TestButtons();
}
}