首先,声明一下这篇文章是为了便于推广所以并没有用全英文书写。
经过了大约一个星期的零零碎碎的时间我终于写出了一个较为完善的QQ登陆界面,其基本上实现了QQ登陆界面应有的功能,并且第一眼看上去你并不会觉得与真正的QQ登陆界面有区别就像这样
当然,很明显,这是一个玩笑。虽然我可以想像在屏幕前的你一定觉得这不好笑。实际上我们要的是这样的笑果(效果?)
任务目标:较为完善的模仿QQ登陆界面。
实现的功能:
1.QQ登陆界面的外观模仿。2.实现了窗体组件的布局管理。
3.实现了去除窗体边框后的最小化,拖动,关闭。
4.实现了鼠标移动到各组件的动画切换效果。
5.实现了弹出菜单的建立。
6.因为每个组件都是单独建立的所以还可以实现图片的快速切换。
个人收获:
1.会熟练运用了BrideLayout 和 FlowLayout 布局管理器
2.熟练掌握了各基本组件的用法。
3.熟练掌握了鼠标监听器的使用方法,并会用构造器传值。
4.了解如何去利用绘图工具去得到一些自己想要图片。
5.基本掌握简单界面的开发过程,并提高了我自主学习,交流的能力,磨练了心智与毅力。
其实,现在回想起来实现一个QQ登陆界面也不难,因为它不可以改变大小,所以开发起来还是很容易的。
下面是重头戏,我的主程序代码。
package awtSwing130709;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.ImageObserver;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
public class QQ130710 extends JPanel{
//定义一个全局变量的监听器类
LoginListener0716 lo;
JFrame qqf;
JButton j1;
JButton j3;
JButton j5;
JButton j4;
JPanel jpin;
Image ii;
JButton jb1;
/**
* 主程序入口
*/
//犯了个大错误不能在主函数写太多 TAT
public static void main(String[] args) {
// 实例化一个对象
QQ130710 qq = new QQ130710();
qq.Frame();
}
// 定义一个获得下方面板的方法
public JPanel getSouth() {
// 实例化一个新面板
JPanel jp = new JPanel();
//加入两个按钮两个透明的标签
jp.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
ImageIcon i1=new ImageIcon("images/8.png");
ImageIcon i2=new ImageIcon("images/9.png");
//多账号登陆
j1=new JButton(i1);
//二维码按钮
JButton j2=new JButton(i2);
JLabel jl1=new JLabel();
JLabel jl2=new JLabel();
jl1.setPreferredSize(new Dimension(65,1));
jl2.setPreferredSize(new Dimension(70,1));
j1.setPreferredSize(new Dimension(52,45));
j2.setPreferredSize(new Dimension(24,25));
j1.setOpaque(false);
j2.setOpaque(false);
//去除按钮边框
j1.setBorderPainted(false);
//给多账号登陆加一个监听器,实现其切换图片效果(内部类)
MouseAdapter qb8=new MouseAdapter(){
public void mouseEntered(MouseEvent e) {
j1.setIcon(new ImageIcon("images/8(1).png"));
}
public void mouseExited(MouseEvent e) {
j1.setIcon(new ImageIcon("images/8.png"));
}
};
j1.addMouseListener(qb8);
//实例化一个按钮对象
JButton jb=new JButton("登 陆");
jb.setActionCommand("login");
//设置按钮的属性
jb.setPreferredSize(new Dimension(150,33));
// jb.setBorderPainted(false);
//设置按钮的位置
jp.setLocation(118, 247);
//给按钮加上监听器
jb.addActionListener(lo);
//添加按钮到画板上
jp.add(j1);
jp.add(jl1);
jp.add(jb);
jp.add(jl2);
jp.add(j2);
//因为是面板所以直接将其设为透明
jp.setOpaque(false);
return jp;
}
// 定义一个获得中间面板的方法
public JPanel getCenter() {
// 实例化一个新面板
JPanel jp = new JPanel();
//设置面板内的流体布局从左对齐
jp.setLayout(new FlowLayout(FlowLayout.LEFT));
//实例化一个下拉框
JComboBox co=new JComboBox();
co.setEditable(true);
//选择添加内容
co.addItem("540767457");
//用于获得下拉框的String
// String l1=co.getSelectedItem().toString();
// System.out.println(l1);
//设置下拉框属性
co.setPreferredSize(new Dimension(187,25));
JLabel jl1=new JLabel("注册账号");
JLabel jl2=new JLabel("找回密码");
//实例化一个密码输入框
JPasswordField jp1=new JPasswordField();
//实例化一个图片
ImageIcon ii = new ImageIcon("images/14.png");
//实例化一个按钮
JButton jb3=new JButton(ii);
jb3.setPreferredSize(new Dimension(22,20));
//去除按钮边框
jb3.setBorderPainted(false);
//设置密码框属性
jp1.setPreferredSize(new Dimension(187,25));
jp1.setLayout(new FlowLayout(FlowLayout.RIGHT,0,0));
//把按钮加入密码输入框
jp1.add(jb3);
//实例化一个监听器用于传递用户名和密码
lo=new LoginListener0716(jp1,co,qqf);
//实例化两个复选框
JCheckBox jc1=new JCheckBox("记住密码");
//复选框 变为透明
jc1.setOpaque(false);
JCheckBox jc2=new JCheckBox("自动登录");
//复选框 变为透明
jc2.setOpaque(false);
//添加组件到面板上面
jp.add(co);
jp.add(jl1);
jp.add(jp1);
jp.add(jl2);
//添加复选框
jp.add(jc1);
jp.add(jc2);
//因为是面板所以直接将其设为透明
jp.setOpaque(false);
return jp;
}
// 定义一个获得左边面板的方法
public JPanel getWest() {
// 实例化一个新面板
JPanel jp = new JPanel();
//设置面板内的流体布局从右对齐
jp.setLayout(new FlowLayout(FlowLayout.RIGHT));
//新建一个面板对象用于存放图片
//用了重绘的方法
jpin = new JPanel(){
public void paint(Graphics g){
g.drawImage(ii, 0, 0, null);
}
};
jpin.setLayout(null );
// 设置面板的属性
jp.setPreferredSize(new Dimension(100, 0));
// 实例化一个图形对象
ImageIcon i = new ImageIcon("images/1.png");
System.out.println("1");
//得到一个image对象
ii=i.getImage();
//因为图形必须依托标签或者按钮才能显示
//创建标签对象并把图片传入
JLabel jl2=new JLabel(i);
/**
* 不能在这取啊
* 不能在这取啊
* 不能在这取啊
* 不能在这取啊
* 是因为画布要在面板可见后取
*/
//在画板上加一个图片
jpin.setPreferredSize(new Dimension(81,81));
//创建一个切换在线状态的按钮
jb1=new JButton(new ImageIcon("images/15.png"));
jb1.setPreferredSize(new Dimension(15,15));
jb1.setBorderPainted(false);
jb1.setBounds(66, 66, 15, 15);
//给最小化加一个监听器,实现其切换图片效果
MouseAdapter lala=new MouseAdapter(){
public void mouseEntered(MouseEvent e) {
jb1.setIcon(new ImageIcon("images/15.png"));
}
public void mouseExited(MouseEvent e) {
jb1.setIcon(new ImageIcon("images/15(1).png"));
}
};
jb1.addMouseListener(lala);
//创建一个状态监听器,实现其弹出窗口效果
stateListener st=new stateListener(jb1);
jb1.addMouseListener(st);
//删除图像下的面板
// jl.setOpaque(false);
//因为是面板所以直接将其设为透明
//把图形加到面板上去
jpin.add(jb1);
jp.add(jpin);
//因为是面板所以直接将其设为透明
jp.setOpaque(false);
// jpin.setOpaque(false);
// jp.add(jl2);
return jp;
}
// 定义一个获得上方面板的方法
public JPanel getNorth() {
// 实例化一个新面板
JPanel jp = new JPanel();
// 设置面板的属性
jp.setPreferredSize(new Dimension(0, 130));
jp.setLayout(new FlowLayout(FlowLayout.RIGHT,0,0));
// 实例化一个图形对象
ImageIcon ii3 = new ImageIcon("images/3.png");
//设置
j3=new JButton(ii3);
//给设置加一个监听器,实现其切换图片效果
MouseAdapter qb3=new MouseAdapter(){
public void mouseEntered(MouseEvent e) {
j3.setIcon(new ImageIcon("images/3(1).png"));
}
public void mouseExited(MouseEvent e) {
j3.setIcon(new ImageIcon("images/3.png"));
}
};
j3.addMouseListener(qb3);
ImageIcon ii4 = new ImageIcon("images/4.png");
//最小化
j4=new JButton(ii4);
//用内部类定义一个最小化的按钮
ActionListener q1=new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
qqf.setExtendedState(qqf.ICONIFIED); //最小化
}
};
j4.addActionListener(q1);
//给最小化加一个监听器,实现其切换图片效果
MouseAdapter qb4=new MouseAdapter(){
public void mouseEntered(MouseEvent e) {
j4.setIcon(new ImageIcon("images/4(1).png"));
}
public void mouseExited(MouseEvent e) {
j4.setIcon(new ImageIcon("images/4.png"));
}
};
j4.addMouseListener(qb4);
ImageIcon ii5 = new ImageIcon("images/5.png");
//关闭
j5=new JButton(ii5);
//设置命令为close
j5.setActionCommand("close");
//在这里我们新定义了一个监听器
//虽然我还不知道为什么如果不新定义一个监听器
LoginListener0716 ll = new LoginListener0716(null, null, qqf);
//给关闭加一个监听器
j5.addActionListener(ll);
//给关闭加一个监听器,实现其切换图片效果
MouseAdapter qb=new MouseAdapter(){
public void mouseEntered(MouseEvent e) {
j5.setIcon(new ImageIcon("images/5(1).png"));
}
public void mouseExited(MouseEvent e) {
j5.setIcon(new ImageIcon("images/5.png"));
}
};
j5.addMouseListener(qb);
//因为是面板所以直接将其设为透明
jp.setOpaque(false);
jp.add(j3);
jp.add(j4);
jp.add(j5);
//将按钮置于右上方
// j5.setBounds(343, 0, 37, 15);
// j5.setOpaque(true);
j3.setPreferredSize(new Dimension(28,15));
j4.setPreferredSize(new Dimension(28,15));
j5.setPreferredSize(new Dimension(35,15));
//去除按钮边框
j3.setBorderPainted(false);
j4.setBorderPainted(false);
j5.setBorderPainted(false);
return jp;
}
// 定义一个初始化QQ窗体的方法
public void Frame() {
// 创建一个新的窗体对象
qqf = new JFrame();
// 设置对象的各个属性
qqf.setTitle("QQ");
qqf.setSize(378, 290);
// qqf.setLocation(500, 250);
qqf.setLocation(new Point(500,200));
qqf.setResizable(false);
qqf.setDefaultCloseOperation(2);
//JFrame 的默认布局是边框布局
// 设置它的边框布局管理器
// BorderLayout BO = new BorderLayout();
// jf.setLayout(BO);
// 把上方的面板加到QQ窗体上
qqf.add(getNorth(), BorderLayout.NORTH);
// 把左边的面板加到QQ窗体上
JPanel qqfw=getWest();
qqf.add(qqfw, BorderLayout.WEST);
// 把中间的面板加到QQ窗体上
qqf.add(getCenter(), BorderLayout.CENTER);
// 把下方的面板加到QQ窗体上
qqf.add(getSouth(), BorderLayout.SOUTH);
/**
* 因为JFrame上有一个图层
* 一个图层又分为好多层
* 然后有些图层是不透明的
* 所以我们的思路就是
* 把BackgrounPicture置于JFrame最底层
* 然后再将面板一一设为透明的即可
*/
//给QQ窗体加入背景
ImageIcon im=new ImageIcon("images/13.png");
//转换为一个标签对象
JLabel JP=new JLabel(im);
//设置填充区域
JP.setBounds(0, 0, im.getIconWidth(),im.getIconHeight());
//将图片置于JLayeredPane面板的最底层
qqf.getLayeredPane().add(JP,new Integer(Integer.MIN_VALUE));
//获取ContentPane面板(就是那个不透明的家伙)
JPanel opacity=(JPanel) qqf.getContentPane();
//把它设为透明的
opacity.setOpaque(false);
//为了模仿的更像 去除掉它的边框吧
qqf.setUndecorated(true);
//对界面加入监听器,使其能拖动
qqf.addMouseMotionListener(lo);
//实现不同的方法应该加入不同的监听器
qqf.addMouseListener(lo);
qqf.setVisible(true);
Graphics g=jpin.getGraphics();
//g.drawImage(ii, 15, 15, null);
}
// public void paint(Graphics g){
// System.out.println("111");
// super.paint(g);//调用父类的重绘方法
// repaint(g);
// }
/**
* 这里主要是用于绘制用户图标的方法
*/
private void repaint(Graphics g){
//得到面板的画布对象,用于画图片
System.out.println("222");
}
}
首先,先申明一下,我这样写是不对的,一个类里面不能实现太多功能,否则你很难去找出错误。由于我前面写过QQ登陆界面的开发,我在这就挑重点讲一下。如何实现了鼠标移动到各组件的动画切换效果,在这里由于只是完成了切换效果,所以我并没有创建新的类去实现,直接用的匿名内部类(这个只在代码较少的情况下使用),事实上这个还是很方便的,还在一定程度上避免了传值市的空指针问题。另外,一定要记住取画布时一定要在窗体可见以后,否则就会出现空指针的问题。
另外,如何给QQ登陆界面加一个状态切换按钮,这个问题你是否想过呢?当想到这时,我头疼了一阵子
就是那个小黄点,这时候你肯定不能在西边的面板加,这时候熊哥给我了一个很好的建议,把图像直接画在面板的画布上,再把小黄点用绝对布局加在面板右下角上。在面板的画布上直接绘制图形真的是一个好方法,希望大家能够熟练掌握。
下面是实现最小化,拖动,关闭的两个监听器对象。其实一个监听器对象可以实现多个功能。
package awtSwing130709;
/**
* JRadioButton 单选按钮
*/
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
/**
* 适配器就是抽象类
* MouseAdapter重写了mouselistener中的所有方法,所以你不用全部实现
* 你只需要重写你所需要的方法
* @author Administrator
*
*/
public class LoginListener0716 extends MouseAdapter implements ActionListener{
private String pass,name;
private JPasswordField jp1;
private JComboBox co;
private JFrame qqf;
// private JButton j5;
Point P;
Point orgin=new Point();
//得到关闭按钮的位置
// Point pj=j5.getLocation();
//重写她的构造方法,用于传递登陆界面的用户名和密码的值
public LoginListener0716(JPasswordField jp1,JComboBox co,JFrame qqf){
this.jp1=jp1;
this.co=co;
this.qqf=qqf;
// this.j5=j5;
}
@Override
public void actionPerformed(ActionEvent e) {
//判断动作执行的对象是否是JButton的实例化的一个对象
if(e.getSource() instanceof JButton){
// System.out.println("fffffffff");
//打印出按钮的命令
System.out.println(e.getActionCommand());
//判断按钮的命令作用
if(e.getActionCommand().equals("close"))
{ System.out.println("dfd");
System.exit(0);}
//如果得到的是登陆命令
if(e.getActionCommand().equals("login")){
//得到用户名和密码
name=co.getSelectedItem().toString();
pass=jp1.getText();
//如果用户名和密码匹配
if(pass.equals("123456")&&name.equals("540767457")){
//实现一个登陆成功的界面
JFrame jf=new JFrame();
jf.setSize(200,150);
jf.setLocation(200,150);
jf.setTitle("Welcome");
jf.setDefaultCloseOperation(3);
JLabel jl=new JLabel("登陆成功");
jf.add(jl);
jf.setVisible(true);
qqf.setVisible(false);
}
else{
//弹出界面第一个参数如果是null就会出现在屏幕中间,如果其他就是在面板中间
JOptionPane.showMessageDialog(qqf, "请填写正确的用户名和密码");
}
}
}
}
//得到最原始的坐标
public void mousePressed(MouseEvent e) {
orgin.x=e.getX();
orgin.y=e.getY();
//System.out.print(orgin.x); System.out.println(orgin.y);
}
//设置一个拖动事件
public void mouseDragged(MouseEvent e){
//获取绝对位置
Point P1=qqf.getLocation();
//重新设置面板位置
qqf.setLocation(P1.x+e.getX()-orgin.x,P1.y+e.getY()-orgin.y);
//qqf.setLocation(e.getX(),e.getY());
}
}
package awtSwing130709;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import javax.swing.JFrame;
public class QQbutton extends MouseAdapter implements ActionListener{
JFrame qqf;
public QQbutton(JFrame qqf){
this.qqf=qqf;
}
//最小化
public void actionPerformed(ActionEvent e) {
qqf.setExtendedState(qqf.ICONIFIED);
}
}
接下啦是实现弹出窗体的方法,在这里我先说一下,现在的我无论用什么方法都去除不了JPopupMenu上JMenuItem上的左边的空白问题,就是左边那个红色的区域(不信大家可以把jp.setUI(new PopupMenuUI(){注释掉)
这时,龙哥告诉了我可以在弹出菜单上的画布上直接画一个这样弹出菜单样式,他的背景色就可以和右边的合二为一了。最终我们就得到了QQ的完美界面。
下面是弹出菜单的代码
package awtSwing130709;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.plaf.PopupMenuUI;
public class stateListener extends MouseAdapter{
private JButton jb1;
public stateListener(JButton jb1) {
this.jb1=jb1;
}
public void mousePressed(MouseEvent e) {
// System.out.println("456");
JPopupMenu jp=new JPopupMenu();
final ImageIcon im16=new ImageIcon("images/55.png");
// jp.setUI(new PopupMenuUI(){
// public void paint(Graphics g, JComponent c){
// g.drawImage(im16.getImage(), 0, 0,101,142, null);
//
// }
// });
// JLabel jl16=new JLabel(im16);
JMenuItem jm=new JMenuItem(im16);
jm.setBackground(Color.RED);
//其默认的Layout是在调试中发现的javax.swing.plaf.basic.DefaultMenuLayout,
//是一个专属的布局Layout继承自BoxLayout
jm.setMargin(new Insets(-10,-20,0,0));
jm.setBorder(null);
jp.setBorder(null);
jp.setPreferredSize(new Dimension(101,142));
jm.setPreferredSize(new Dimension(101,142));
// jm.setIcon(im16);
jp.setLayout(null);
jm.setLayout(null);
//jm.setBounds(-5, -5, 100, 100);
//jp.add(jm);
jp.insert(jm, 0);
// jp.setPopupSize(new Dimension(101,142));
//jp.setPreferredSize(new Dimension(110,149));
jp.setOpaque(false);
jp.setBackground(Color.WHITE);
jp.setBorderPainted(false);
jp.setVisible(true);
jp.show(jb1, 0, 15);
}
}
后记:其实,“完美”QQ登陆界面并不完美,登陆按钮其实可以用贴图,还有QQ登陆窗体上的圆角,
以及标签,键盘的切换效果,还有弹出菜单我只加了一个ITEM也就是一张图,偷了下懒。这是我的第一篇产品总结,希望有大神能指点一二,我先在此谢过了。