- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在做表格。我想从数据库中获取数据。我想要 3 个按钮打开、编辑、删除以及每条获取的记录。我已经完成了记录的获取。我在添加时遇到问题按钮到 JTable。我也遇到从字符串到“日期”的日期转换问题。我使用的数据库是MySql 5.1。
import java.awt.event.*;
import javax.management.openmbean.OpenDataException;
import javax.swing.*;
//import java.awt.*;
import javax.swing.table.DefaultTableModel;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Date;
import java.util.regex.*;
class frameRegistry extends JFrame implements ActionListener
{
/**
*
*/
private static final long serialVersionUID = 1L;
// ----------------------------------PANELS--------------------------------------
JPanel panelImage, panelDate, panelAddForm, panelSearch,
panelDisplay;
// -----------------------GUI ELEMENTS------------------------------------------
// -----------------------------------------------------------------------------
JButton addRecord, searchHistory, save, cancel;
JLabel labelName, labelFirstName, labelMiddleName, labelLastName,
labelBirthDate, labelAge, labelCity, labelContact, labelImage,
labelDate, labelValidity, labelAmount, labelNote,labelTime;
JLabel demo;
JTextField textFieldFirstName, textFieldMiddleName, textFieldLastName,
textFieldAge, textFieldCity, textFieldContact, textFieldValidity,
textFieldAmount, textFieldNote;
JTextField textFieldNameSearch;
JTable table;
JScrollPane scrollPane;
Calendar currentDate, validitydate;
SimpleDateFormat sdf;
Date validity;
int age, amount;
Double contact;
int flag = 0;
String Year, Month, Day, stringValidityDate;
String firstName, middleName, lastName, city;
String stringnamesearch;
String time;
// ---------------------DATABASEVARIABLES-----------------------------------------
// -------------------------------------------------------------------------------
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
String url = "jdbc:mysql://localhost:3306/records";
String driver = "com.mysql.jdbc.Driver";
String userName = "root";
String password = "";
// ------------------COMPONANT ARRAYS------------------------------------------
// ----------------------------------------------------------------------------
JButton open[];
JButton edit[];
JButton delete[];
// -----------------------FRAME STARTS---------------------------------------------
//---------------------------------------------------------------------------------
frameRegistry( )
{
//-----------------------------------------------------------------------------
setSize( 600, 800 );
setDefaultLookAndFeelDecorated( true );
setVisible( true );
setLayout( null );
labelImage = new JLabel( new ImageIcon( "C:\\Users\\SUN\\Desktop
\\logo.png" ) );
panelImage = new JPanel( );
panelImage.add( labelImage );
panelImage.setBounds( 0, 0, 700, 90 );
add( panelImage );
currentDate = Calendar.getInstance( );
Year = "" + currentDate.get( Calendar.YEAR );
Month = "" + currentDate.get( Calendar.MONTH );
Day = "" + currentDate.get( Calendar.DAY_OF_MONTH );
time = "" + currentDate.get( Calendar.HOUR_OF_DAY ) + ":"
+ currentDate.get( Calendar.MINUTE );
labelDate = new JLabel( "Date:" + Day + "/" + Month + "/" + Year + " "
+ time );
panelDate = new JPanel( );
panelDate.add( labelDate );
panelDate.setBounds( 350, 100, 130, 20 );
add( panelDate );
panelSearch = new JPanel( );
panelSearch.setLayout( null );
addRecord = new JButton( "Add Record" );
addRecord.setBounds( 5, 10, 100, 30 );
addRecord.addActionListener( this );
panelSearch.add( addRecord );
// ------------------------NAME SEARCH IN DATABASE-----------------------
textFieldNameSearch = new JTextField( );
textFieldNameSearch.setBounds( 150, 10, 100, 30 );
textFieldNameSearch.addKeyListener( new KeyAdapter( ) {
public void keyTyped( KeyEvent e ) {
String input = textFieldNameSearch.getText( );
Pattern p = Pattern.compile( "[ 0-9,^$,&%$#@!()*^]" );
Matcher m = p.matcher( input );
if ( m.find( ) ) {
JOptionPane.showMessageDialog( null, "Please enter valid Name",
"Sorry", JOptionPane.ERROR_MESSAGE );
}
}
} );
panelSearch.add( textFieldNameSearch );
searchHistory = new JButton( "Search" );
searchHistory.setBounds( 270, 10, 100, 30 );
searchHistory.addActionListener( this );
panelSearch.add( searchHistory );
panelSearch.setBounds( 0, 130, 450, 50 );
add( panelSearch );
panelAddForm = new JPanel( );
panelAddForm.setLayout( null );
panelDisplay = new JPanel( );
panelDisplay.setLayout( null );
//------------------------NAME------------------------------------------------
labelName = new JLabel( "Name" );
labelName = new JLabel( "Name" );
labelName.setBounds( 20, 10, 50, 20);
panelAddForm.add(labelName);
//-------------------------FNAME------------------------------------------------
labelFirstName = new JLabel("First Name");
labelFirstName.setBounds(100, 30, 80, 10);
panelAddForm.add(labelFirstName);
textFieldFirstName = new JTextField( );
textFieldFirstName.setBounds( 100, 10, 80, 20 );
textFieldFirstName.addKeyListener( new KeyAdapter( ) {
public void keyTyped( KeyEvent e ) {
String input = textFieldFirstName.getText( );
Pattern p = Pattern.compile( "[ 0-9,&%$#@!()*^,\t\n\f\r]");
Matcher m = p.matcher( input );
if ( m.find( ) ) {
JOptionPane.showMessageDialog( null, "Please Enter Valid Name",
"Sorry", JOptionPane.ERROR_MESSAGE );
}
}
} );
panelAddForm.add( textFieldFirstName );
//----------------------------------------MNAME----------------------------------
labelMiddleName= new JLabel("Middle Name");
labelMiddleName.setBounds( 190, 30, 80, 10);
panelAddForm.add(labelMiddleName);
textFieldMiddleName = new JTextField( );
textFieldMiddleName.setBounds( 190, 10, 80, 20 );
textFieldMiddleName.addKeyListener( new KeyAdapter( ) {
public void keyTyped( KeyEvent e ) {
String input = textFieldMiddleName.getText( );
Pattern p = Pattern.compile( "[ 0-9,&%$#@!()*^]" );
Matcher m = p.matcher( input );
if ( m.find( ) ) {
JOptionPane.showMessageDialog( null, "Please Enter Valid
Name","Sorry", JOptionPane.ERROR_MESSAGE );
}
}
} );
panelAddForm.add( textFieldMiddleName );
//-----------------------------------labelName----------------------------------------
labelLastName = new JLabel("Last Name");
labelLastName.setBounds(280, 30, 80, 10);
panelAddForm.add(labelLastName);
textFieldLastName = new JTextField( );
textFieldLastName.setBounds( 280, 10, 80, 20 );
textFieldLastName.addKeyListener( new KeyAdapter( ) {
public void keyTyped( KeyEvent e ) {
String input = textFieldLastName.getText( );
Pattern p = Pattern.compile( "[ 0-9,&%$#@!()*^]" );
Matcher m = p.matcher( input );
if ( m.find( ) ) {
JOptionPane.showMessageDialog( null, "Please Enter Valid Name",
"Sorry", JOptionPane.ERROR_MESSAGE );
}
}
} );
panelAddForm.add( textFieldLastName );
//-------------------------------------BDATE--------------------------------------
labelBirthDate = new JLabel( "Birth Date" );
labelBirthDate.setBounds( 20, 60, 60, 20 );
panelAddForm.add( labelBirthDate );
//--------------------------------------------AGE---------------------------------------
labelAge = new JLabel( "Age" );
labelAge.setBounds( 20, 110, 50, 20 );
panelAddForm.add( labelAge );
textFieldAge = new JTextField( );
textFieldAge.setBounds( 100, 110, 80, 20 );
textFieldAge.addKeyListener( new KeyAdapter( ) {
public void keyTyped( KeyEvent e ) {
String input = textFieldAge.getText( );
Pattern p = Pattern.compile( "[ A-Z,a-z,&%$#@!()*^]" );
Matcher m = p.matcher( input );
if ( m.find( ) ) {
JOptionPane.showMessageDialog( null, "Numbers only",
"Sorry", JOptionPane.ERROR_MESSAGE );
}
}
} );
panelAddForm.add( textFieldAge );
//-------------------------------------CITY----------------------------------------------
labelCity = new JLabel( "City" );
labelCity.setBounds( 20, 160, 80, 20 );
panelAddForm.add( labelCity );
textFieldCity = new JTextField( );
textFieldCity.addKeyListener( new KeyAdapter( ) {
public void keyTyped( KeyEvent e ) {
String input = textFieldCity.getText( );
Pattern p = Pattern.compile( "[ 0-9,&%$#@!()*^]" );
Matcher m = p.matcher( input );
if ( m.find( ) ) {
JOptionPane.showMessageDialog( null, "Characters only",
"Sorry", JOptionPane.ERROR_MESSAGE );
}
}
} );
textFieldCity.setBounds( 100, 160, 80, 20 );
panelAddForm.add( textFieldCity );
//------------------------------------------CONTACT-----------------------------
labelContact = new JLabel( "Contact" );
labelContact.setBounds( 20, 210, 60, 20 );
panelAddForm.add( labelContact );
textFieldContact = new JTextField( 12 );
textFieldContact.setBounds( 100, 210, 80, 20 );
textFieldContact.addKeyListener( new KeyAdapter( ) {
public void keyTyped( KeyEvent e ) {
String input = textFieldContact.getText( );
Pattern p = Pattern.compile( "^[ 1-9][ 0-9]{12}$" );
Matcher m = p.matcher( input );
if ( m.find( ) ) {
JOptionPane.showMessageDialog( null, "Numbers only",
"Sorry", JOptionPane.ERROR_MESSAGE );
}
}
} );
panelAddForm.add( textFieldContact );
// ----------------------------------------VALIDITY-----------------------
labelValidity = new JLabel( "Valiidity" );
labelValidity.setBounds( 20, 260, 60, 20 );
panelAddForm.add( labelValidity );
textFieldValidity = new JTextField( );
textFieldValidity.setBounds( 100, 260, 80, 20 );
panelAddForm.add( textFieldValidity );
//------------------------------------------NOTE------------------------------------
labelNote = new JLabel( "Note" );
labelNote.setBounds( 20, 310, 60, 20 );
panelAddForm.add( labelNote );
textFieldNote = new JTextField( );
textFieldNote.setBounds( 100, 310, 80, 20 );
textFieldNote.addKeyListener( new KeyAdapter( ) {
public void keyTyped( KeyEvent e ) {
String input = textFieldNote.getText( );
Pattern p = Pattern.compile( "[ 0-9,&%$#@!( )*^]" );
Matcher m = p.matcher( input );
if ( m.find( ) ) {
JOptionPane.showMessageDialog( null, "Characters only",
"Sorry", JOptionPane.ERROR_MESSAGE );
}
}
} );
panelAddForm.add( textFieldNote );
//----------------------------------------FEES-------------------------------------------
labelAmount = new JLabel( "Fees" );
labelAmount.setBounds( 20, 360, 60, 20 );
panelAddForm.add( labelAmount );
textFieldAmount = new JTextField( );
textFieldAmount.setBounds( 100, 360, 80, 20 );
textFieldAmount.addKeyListener( new KeyAdapter( ) {
public void keyTyped( KeyEvent e ) {
String input = textFieldAmount.getText( );
Pattern p = Pattern.compile( "[ A-Z,a-z,&%$#@!( )*^]" );
Matcher m = p.matcher( input );
if ( m.find( ) ) {
JOptionPane.showMessageDialog( null, "Numbers only",
"Sorry", JOptionPane.ERROR_MESSAGE );
}
}
} );
panelAddForm.add( textFieldAmount );
//----------------------------------------------------------------------------------
save = new JButton( "SAVE" );
save.setBounds( 25, 410, 70, 20 );
save.addActionListener( this );
panelAddForm.add( save );
cancel = new JButton( "CANCEL" );
cancel.setBounds( 150, 410, 80, 20 );
cancel.addActionListener( this );
panelAddForm.add( cancel );
panelAddForm.setBounds( 0, 220, 600, 700 );
panelAddForm.setVisible( false );
// ---------------------------ADD FORM COMPLETE-----------
panelDisplay.setBounds( 0, 200, 800, 600 );
}
// -------------------BUTTON EVENTS START-------------------------
public void actionPerformed( ActionEvent ae )
{
int actionCount=0;
if ( ae.getSource( ) == addRecord )
{
remove(panelDisplay);
add( panelAddForm );
panelAddForm.setEnabled( true );
panelAddForm.setVisible( true );
validitydate = Calendar.getInstance( );
validitydate.add( Calendar.DAY_OF_MONTH, 90 );
stringValidityDate = "" + validitydate.get( Calendar.DAY_OF_MONTH )
+ "/" + validitydate.get( Calendar.MONTH ) + "/"
+ validitydate.get( Calendar.YEAR );
textFieldValidity.setText( stringValidityDate );
textFieldValidity.setEnabled( false );
}
if ( ae.getSource( ) == save ) {
firstName = textFieldFirstName.getText( );
middleName = textFieldMiddleName.getText( );
lastName = textFieldLastName.getText( );
age = Integer.parseInt( textFieldAge.getText( ) );
city = textFieldCity.getText( );
int flag = 0;
String cnt = "" + textFieldContact.getText( );
if ( cnt.length( ) < 6 ) {
flag = 1;
}
contact = Double.parseDouble( textFieldContact.getText( ) );
if ( flag == 1 ) {
JOptionPane.showMessageDialog( null,
"Enter valid phone number",
"Sorry", JOptionPane.ERROR_MESSAGE );
} else {
try {
Class.forName( driver ).newInstance( );
connection = DriverManager.getConnection( url,
userName, password );
statement = connection.createStatement(
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE );
System.out.println( "Connected to database" );
resultSet = statement.executeQuery( "select *
from record" );
resultSet.moveToInsertRow( );
resultSet.updateString( 1, firstName );
resultSet.updateString( 2, middleName );
resultSet.updateString( 3, lastName );
resultSet.updateInt( 5, age );
resultSet.updateDouble( 6, contact );
resultSet.updateString( 7, city );
resultSet.updateDate( 8, ( java.sql.Date ) validity );
resultSet.updateInt( 9, amount );
resultSet.insertRow( );
JOptionPane.showMessageDialog( null,
"Record Added","Success",
JOptionPane.INFORMATION_MESSAGE );
panelAddForm.setEnabled(false);
panelAddForm.setVisible( false );
connection.close( );
}
catch ( Exception e ) {
e.printStackTrace( );
JOptionPane.showMessageDialog( null,
"Insertion failed",
"Sorry", JOptionPane.ERROR_MESSAGE );
}
}
}
if ( ae.getSource( ) == cancel ) {
textFieldFirstName.setText( "" );
textFieldMiddleName.setText( "" );
textFieldLastName.setText( "" );
textFieldAge.setText( "" );
textFieldCity.setText( "" );
textFieldContact.setText( "" );
textFieldValidity.setText( "" );
textFieldAmount.setText( "" );
panelAddForm.setEnabled( false );
panelAddForm.setVisible( false );
}
if ( ae.getSource( ) == searchHistory )
{
panelAddForm.setEnabled( false );
panelAddForm.setVisible( false );
remove( panelAddForm );
add( panelDisplay );
stringnamesearch = "" + textFieldNameSearch.getText( );
DefaultTableModel tableModel = new DefaultTableModel( );
if(stringnamesearch=="")
{
JOptionPane.showMessageDialog( null, "Search is blank",
"Sorry", JOptionPane.ERROR_MESSAGE );
}
else
{
try
{
Class.forName( driver ).newInstance( );
connection = DriverManager.getConnection( url,
userName,password );
statement = connection.createStatement(
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE );
resultSet = statement.executeQuery( "select * from record
where firstname = '"+ stringnamesearch+
"'or lastname = '" + stringnamesearch + "'" );
System.out.println( "Query executed" );
String firstName;
String lastName;
int counter = 0;
JButton add=new JButton("ADD");
while ( resultSet.next( ) )
{
firstName = resultSet.getString( 1 );
lastName = resultSet.getString( 3 );
String[ ] columnNames = { "First Name",
"Last Name","click" };
Object[ ] data = { "" + firstName, "" +
lastName, add };
tableModel.setColumnIdentifiers( columnNames );
tableModel.addRow( data );
tableModel.fireTableDataChanged();
counter++;
}
table = new JTable( tableModel );
table.setEnabled(false);
scrollPane = new JScrollPane( table );
scrollPane.setBounds( 10, 10, 350, 100 );
scrollPane.revalidate();
panelDisplay.add( scrollPane );
connection.close( );
System.out.println( "" + counter );
//------------- creating array of Buttons---------------------------------
open=new JButton[counter];
edit=new JButton[counter];
delete=new JButton[counter];
for( int i=0,y=30; i<counter;i++,y+=15 )
{
open[i]=new JButton( "Open" );
System.out.println("1st: "+i);
open[i].setBounds( 380, y, 70, 15 );
System.out.println("2nd: "+i);
open[i].addActionListener( this );
panelDisplay.add (open[i] );
System.out.println("3rd: "+i);
edit[i]=new JButton( "Edit" );
edit[i].setBounds( 460, y, 70, 15 );
edit[i].addActionListener( this );
panelDisplay.add( edit[i] );
delete[i]=new JButton( "Delete" );
delete[i].setBounds( 540, y, 70, 15 );
delete[i].addActionListener( this );
panelDisplay.add( delete[i] );
System.out.println(""+i);
}
actionCount=open.length;
panelDisplay.setEnabled(false);
panelDisplay.setVisible(true);
}
catch ( Exception e )
{
e.printStackTrace( );
}
}
}
for( int j=0;j<open.length;j++ )
{
if( ae.getSource() == open[j] )
{
System.out.println("open of"+j+"is clicked");
fetchData(j);
}
}
//-----------------BUTTON EVENT ENDS----------------------------------------
}
public void fetchData(int i )
{
panelDisplay.setEnabled(false);
panelAddForm.setEnabled(false);
panelDisplay.setVisible(false);
panelAddForm.setVisible(false);
remove(panelDisplay);
remove(panelAddForm);
JPanel showRecord=new JPanel();
showRecord.setLayout(null);
showRecord.setBounds(5, 300, 600, 700);
int id=i;
int uniqid=0;
String firstName="", lastName="";
try
{
Class.forName( driver ).newInstance( );
connection = DriverManager.getConnection( url, userName, password );
statement = connection.createStatement(
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE );
resultSet = statement.executeQuery( "select * from record
where uniqid="+id );
System.out.println( "Query executed" );
while(resultSet.next())
{
firstName = resultSet.getString(1);
lastName = resultSet.getString(3);
uniqid = resultSet.getInt(11);
}
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println("name was:"+firstName+" id is"+uniqid);
JLabel labelfirstName=new JLabel(firstName);
labelfirstName.setBounds(30,30,60,30);
showRecord.add(labelfirstName);
JLabel labellastName=new JLabel(lastName);
labellastName.setBounds(80,30,60,30);
showRecord.add(labellastName);
add(showRecord);
}
}
class Registry {
public static void main( String args[ ] ) {
frameRegistry reg = new frameRegistry( );
}
}
最佳答案
不要使用空布局和 setBounds。 Swing 被设计为与布局管理器一起使用。阅读 Layout Managers 上的 Swing 教程.
不要在文本字段上使用 KeyListener。如果用户将文本粘贴到文本字段中会发生什么?相反,您应该使用 DocumentListener。阅读 How to Write a Document Listener 上的教程.
I got problem in adding the button to JTable
Table Button Column展示了一种实现此目的的方法。
关于java - 从数据库获取数据并将其与 JButton 一起显示在表格上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16101226/
本质上,我编写的是一个益智游戏。 它包含一个图像,该图像进一步分为 9 block ,放置在包含 3x3 JButton GridLayout 的 JPanel 上。最初,9 个按钮是空的。当用户点击
我正在制作一个游戏,其中有一个名为 move(int x1, int y1, int x2, int y2) 的方法,该方法将棋子从第一个按钮 (x1,y1) 移动并将其放置在第二个按钮 (x2, y
我使用 NetBeans 创建了一个框架。该框架有两个按钮 A 和 B。按钮 A 最初被禁用。仅当单击按钮 B 时才启用。 public newFrame() { //newFrame is t
我想使用 MouseListener 从按钮矩阵中删除某个按钮,并在空白处添加 JLabel,所以我使用: import java.awt.*; import java.awt.event.*; im
我正在创建一个黑白棋游戏,想知道如何在单击时将按钮文本从 B 更改为 W,反之亦然。 我尝试将 Action 监听器添加到我的 forloop 中,这为游戏创建了我的板,当我单击标记为 W 的按钮时,
我的项目中有 7 个按钮。其中有 6 个类别,RandomSoru 按钮是随机选择其中一个类别的按钮。我想访问所选类别。 “r”是随机生成器。 RandomSoru.addActionListener
我对此感到好奇,因为我们正在 Swing 中制作游戏,并且出于某种原因将 map 图 block 制作为 jButtons 而不是 jPanels。现在我们想将单位放在它们上面,这样当单位位于它们上面
我创建了一个按钮数组: JButton bt[][]=new JButton[8][8]; 然后我通过以下方式调用一个名为 refreshBoard 的函数 public void refreshBo
我想在这篇文章的序言中告诉大家,这是我第一次发帖,所以如果有任何错误,请告诉我。 我正在尝试为我的高中计算机数学(编程)课编写一款二十一点游戏,但出现了很多错误,但真正令人烦恼的是这个错误。 我的 G
我正在创建一个“谁想成为百万富翁”游戏,并创建了一个半按钮,我想使用它来删除两个 JButton 答案。以下是两个作为答案选项的 JButton 的代码。 enter code here: Answe
我有一个 JButton,我想在按下它时创建一个新的 JButton,我添加了一个如下所示的 ActionListener,但它没有添加另一个 JButton。 public void actionP
如果在 JTextBox 中输入字符串,然后按“输入按钮”,它会在 JTextField 中返回正确的数据,如果我更改字符串,然后重新按输入,也会返回正确的数据。如果我按“输入按钮”然后按“添加”按钮
我想在单击另一个 jbutton 时获得一个 jbutton。 Here the link for sample code(Log in as jbutton,asdf as a password)
假设我创建了一个带有 jbuttons 的 2d tile map ,然后在 map 顶部创建了单位,当单位(也是一个 jbutton)位于 tile 顶部时,有没有办法显示 map 的背景,因为如何
我正在开发一个项目,我需要单击一个按钮来创建另一个按钮。最终,我希望对新按钮的位置有更多的控制,并能够多次创建新按钮,但现在......我希望只让一个 JButton 创建另一个 JButton。 使
JPanel 中有 12 个 JButton。我想单击其中一个并禁用所有其他(它将“突出显示”)。然后,如果我单击禁用的一个,则前一个将被禁用,并且过程是相同的。考虑到有 12 个按钮并且我想避免重复
我正忙于用 Java 制作游戏。然而,我正在努力让 GUI 正常工作。 我遇到的问题: 当按下按钮时,我希望它显示一个彩色圆圈,当再次按下按钮时,我希望它在旧圆圈周围画一个圆圈,这可能会发生,直到每个
大家好,我正在尝试使用 Java 创建一个简单的国际象棋游戏。我有一个 [8][8] 数组的 JButton 板。我为每个分配一个新的 SquareListener,它是一个扩展 BoardListn
我有 JButtons“暂停”和“取消暂停”。当用户暂停程序时,应禁用“暂停”按钮,并启用“取消暂停”按钮。我不知道怎么写。取消暂停按钮有效,但暂停按钮不起作用,因为“无法解决取消暂停”。怎么处理呢?
我设置了一个网格布局,中间有 16 个按钮。我在第一个按钮上放置了一个图标。 我将如何循环,当用户选择网格上的下一个按钮时,它将图标从旧位置 move 到新位置? private ArrayList
我是一名优秀的程序员,十分优秀!