|
|
||
Patrick Keegan's BlogCommunity: NetBeans ArchivesDraft of Custom Desktop Database TutorialPosted by pkeegan on June 24, 2008 at 09:17 AM | Permalink | Comments (0)I have published a draft of an extended tutorial on creating desktop Java applications on netbeans.org. The tutorial is based on my recent series of blog posts. Thanks to everybody who provided questions and suggestions! A lot of them have been incorporated into the tutorial. Others are on my to-do list and are not forgotten. The main things that appear in the tutorial that were missing from the blog are currency and date rendering and more customizations of table columns. The tutorial needs some more polishing, but I think it's in a reasonably useful state. Let me know what you think. By the way, I'm going on vacation tomorrow, so excuse the upcoming silence. Talk to you in three weeks. Using Beans Binding to Search in a TablePosted by pkeegan on June 05, 2008 at 10:42 AM | Permalink | Comments (2)Now and again someone will ask me how you can search records in a desktop database app. Here's a reasonably simple way to do so, using mechanisms that exist in Swing and the Beans Binding library. We will create a binding between the rowSorter property of the master table in the example in my previous entries and a text field that I've just added for the search string. For this binding we will need a binding converter so that the table knows how to respond to the search string. To follow along, you can either continue with the project created in previous entries or begin with a new NetBeans project (Java Desktop Application project template) that connects to a database. Let's get started. First of all, we'll add a label and a text field for the search field as shown below.
Now we will add a converter class to the project.
We'll use this converter when we create the binding. To create the binding:
Now when you run the application, you should be able to type in the Search Filter field and see that the list of rows is reduced to only rows that contain text matching what you have typed.
Note: If you have been following this whole series of posts, you will need to make a few changes to get the New Record and Edit Record buttons to work correctly. The Edit Record button doesn't work correctly because the number of the record to display is determined according to the records displayed but applied to the whole list of records in the database. In other words, if you select the first record in a filtered list, the first record of the whole database appears for editing in the dialog.
The New Record button fails with an exception because the code to select the new row is determined according to number of records in the database table, not according to the number of records currently displayed in the table. To fix the first problem, replace the line: ec.setCurrentRecord(list.get(masterTable.getSelectedRow())); with: ec.setCurrentRecord(list.get(masterTable.convertRowIndexToModel(masterTable.getSelectedRow()))); To fix the second problem, replace the line: int row = list.size() - 1; with: int row = masterTable.getRowCount() - 1; Passing Dialog Input to the Main View and DatabasePosted by pkeegan on May 27, 2008 at 08:33 PM | Permalink | Comments (3)This is the fourth in a series of posts on creating a Java database application. In my last few posts, I started with skeleton code generated by the IDE and provided my own customizations, including adding a dialog to use for data entry and binding those fields with a table on the main form. In this post, I finish coding the connection between the dialog and the main form. I'll also add an Edit Client button and its corresponding Action code to the main form. First let's hook up the buttons in the EditClient dialog with appropriate event-handling code. We already have save() and refresh() actions that are provided with the skeleton application. We will code the dialog so that the buttons reuse these actions. We can accomplish this by setting up a boolean property in the dialog that returns true when the Save Record button is pushed and returns false when Cancel is selected. Based on the value that is returned when the dialog is closed, the the To set up the property, do the following:
We'll set this property's value in event handling code for the buttons. Let's create the event listeners and handlers now:
Navigate to the
if (ec.isClientConfirmed()) {
save().run();
} else {
refresh().run();
}
In the RefreshTask inner class, Since the To make the dialog modal:
To make the main form's Clients table uneditable:
You can now run the application and click New Client to add a new record. When you press Save in the New Client dialog, the record is saved. When you press Cancel, the new record you have changed is rolled back. This is all well and good, but by disabling the editability of the table on the main form, we can no longer edit existing records. To solve this, we'll add an Edit button to the main client form so that we can edit existing records. For event-handling, we'll take advantage of the Swing Application Framework's Action facility. To add the button and its corresponding event-handling code, do the following:
Most of that code is copied straight from the newRecord action. The key difference is the line
The Client part of the application is almost completely set. You should be able to freely add, edit, and delete records from your CLIENTS table using the specialized GUI we have created. One last detail: the main form still has the title of Database Application Example, and it's not obvious where to change. Hint: it's not within the GUI Builder. To change the title of the main frame of the application:
Now when you run the application, most of the key elements are in place. In the screenshot below, you can see the Edit Client dialog as it appears after having selected a record and pressed the Edit button.
I could continue with customization of the bottom part of the main form and other fine tuning of the application, but I'll save most of those details for the tutorial and individual blog posts with more atomic examples. As always, keep your questions coming and I'll try to deal with as many of them as I can. Beans Binding Between Separate FormsPosted by pkeegan on May 21, 2008 at 07:45 PM | Permalink | Comments (15)Continuing from my last post, I'll show the next steps in the creation of this simple (but not too simple) client purchase application. This time, our main focus is in creating a separate dialog which we will use for data entry. We'll need to do a few tricks so that input from the dialog is propagated to the main form and then the database. But first we'll need to clear up a few loose ends. As I alluded to last time, I use AUTO_INCREMENT attributes for the ID columns of the CLIENTS, COUNTRIES, and ORDERS tables. This means that whenever a new row is added to those tables, that row's AUTO_INCREMENT field is given a unique value (the value of the last new record + 1). For me using AUTO_INCREMENT is a handy way to ensure having unique records. When you generate the skeleton of the application in the New Java Desktop Application wizard, the IDE generates two entity classes (Clients.java and Orders.java) that represent database tables with the same names. However, these entity classes are missing code to deal with the AUTO_INCREMENT fields. Without that code, you will get errors when trying to enter new records. To fix that:
Note: You can also use code completion here. It takes three selections to get the entire line, but the import statements are generated for free. Once you have added these annotations, you can run the application and start adding data. Click the top New button to add a client. With a client selected, click the bottom New button to add an order for that client. Click Save to push your changes to the database. Click Refresh to back out any unsaved changes.
I like tables for browsing data, but I think they leave something to be desired for data entry. So for this application, we'll add dialogs for data entry. To create and populate the JDialog, follow these steps:
The resulting layout should look something like what you see below.
Now we need to bind the various fields to the corresponding columns in the table. We can't bind directly to components from other forms in the Bind dialog box, so we'll have to create an intermediary property of type Clients to hold the record. When the user presses New, the property will be given the value of the currently selected record. We can quickly generate the bean property with the IDE's bean support:
We now need to customize the generated
Clients oldRecord = this.currentRecord;
this.currentRecord = currentRecord;
propertyChangeSupport.firePropertyChange("currentRecord", oldRecord, currentRecord);
Now we need to add code to the New action to open the dialog and clear the currentRecord property when a user wants to add a new record:
JFrame mainFrame = ClientAndPurchaseApp.getApplication().getMainFrame();
EditClient ec = new EditClient(mainFrame, false);
ec.setCurrentRecord(c);
ec.setVisible(true);
For now, we won't code the Save and Cancel buttons on the dialog (we've had enough digressions!). I'll cover that in an upcoming post. With those preliminaries out of the way, we can proceed with the binding of the text fields. We'll be binding the To bind a dialog text field to the appropriate property of
Do this procedure for each of the text fields in the dialog. For now, don't bind the JComboBox to anything. We'll need to do some other preparation to get that to work properly. I'll cover that in my next post. Now you should be able to run the application, press the first New button, and enter data in the dialog. The Save and Cancel buttons on the dialog don't do anything yet, but we can save the records from the main frame. In the next post, we'll clear up some of these loose ends so that the application behaves more like applications that we are used to. Input on a New Desktop Java Database TutorialPosted by pkeegan on May 13, 2008 at 09:20 AM | Permalink | Comments (14)Recently I've found time again to work on actual tutorials. I don't have anything written yet, but I have something resembling a plan, which you can find here: http://wiki.netbeans.org/PlanGuiBuilderDocImprovements. Over the next few weeks, I'll be blogging about creating a Swing desktop application with database connectivity. These postings will essentially serve as a rough sneak preview of a full-fledged tutorial on the subject that I'll later post to netbeans.org. The tutorial will go beyond simple database connectivity and show things such as one-to-many and many-to-one relationships as well as how to bind database tables to a variety of GUI components. We'll use a MySQL database that has tables for client info, order info, and countries. There will be a one-to-many relationship between the client and order tables. There will be a many-to-one relationship between client and countries tables. Along the way, I'll be looking at any feedback that comes through and do my best to respond to it, whether in quick responses, in separate articles, or by modifying the final tutorial. Chances are that I'll also tweak the structure along the way as I find better ways of doing things. To start off, I'll provide an SQL script that provides a beginning database structure:
CREATE TABLE CLIENTS (
ID INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
FIRST_NAME VARCHAR(20),
SURNAME VARCHAR(30),
ADDRESS VARCHAR(30),
CITY VARCHAR(30),
STATE_ VARCHAR(30),
ZIP INTEGER,
COUNTRY_ID INTEGER,
PHONE INTEGER
);
CREATE TABLE EMAIL_ADDRESSES (
CLIENT_ID INTEGER NOT NULL,
ADDRESS VARCHAR(50) NOT NULL PRIMARY KEY,
FORMAT INTEGER,
FOREIGN KEY (CLIENT_ID) REFERENCES CLIENTS(ID)
);
CREATE TABLE ORDERS (
ID INTEGER NOT NULL AUTO_INCREMENT,
CLIENT_ID INTEGER NOT NULL,
PRODUCT VARCHAR(50) NOT NULL,
AMOUNT INTEGER NOT NULL,
PRIMARY KEY(ID),
FOREIGN KEY (CLIENT_ID) REFERENCES CLIENTS(ID)
);
CREATE TABLE PRODUCTS (
MODEL VARCHAR(50) NOT NULL PRIMARY KEY,
PRICE DECIMAL NOT NULL
);
CREATE TABLE COUNTRIES (
COUNTRY_ID INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
COUNTRY VARCHAR(30)
);
ALTER TABLE CLIENTS
ADD CONSTRAINT COUNTRIES_FK Foreign Key (COUNTRY_ID)
REFERENCES COUNTRIES (COUNTRY_ID);
A few notes on the structure:
After you have created the above database and have connected to it from IDE (see Connecting to a MySQL Database), you can go ahead and create the initial application skeleton by following these steps:
So that's the start of the application. The next steps include:
I'll cover those topics and more starting early next week. I welcome all feedback! JavaHelp and Swing Application FrameworkPosted by pkeegan on May 15, 2007 at 07:27 AM | Permalink | Comments (6)Updated 27 March 2008 to account for changes that appeared in NetBeans IDE 6.0 (and are still relevant for 6.1)
After a long long hiatus, I'm going to try my hand at blogging again. The main reason is to share things that I learn in my work in a more frequent and incremental way than I do with the tutorials I write. I expect this will also give me a nice chance to have more onversations with readers than you do when you are buried behind more monolothic documents. In doing this, I'm obviously taking a few cues from Geertjan.
Let's do a run-through of this process using my favorite IDE, NetBeans. To spice things up a little, I'll use the NetBeans IDE 6.0 Preview (M9) release. This release is pretty far from final, but it's got a lot of cool things worth showing off, including support for the Swing Application Framework. The most visible impact on this mini-tutorial will be the snazzy application skeleton you get without coding anything plus a simple way to handle actions. If you prefer to use the 5.5 version, the most essential points here will work. You just won't see the fancy new template or the Actions part of the Swing Application Framework in, ahem, action. First we'll create a skeleton application that already has menus and windowing behavior built in.
To get the help set into your project directory:
Now we have to make sure that the IDE knows to package the JavaHelp files in the application as part of the build process:
appwithhelp.docs package. A couple of dummy help topics are in appwithhelp.docs.content. For info on the metadata files and how JavaHelp works in general, check out the JavaHelp User's Guide.
Quick digression: Metadata for JavaHelp help sets are simple XML files. In the JavaHelp documentation, you might notice that these files have special extensions (like .hs, .jhm, .idx, and .toc). However, we're using .xml as the extensions for these files so that we don't have to do any extra configuring to get the IDE's XML editing features for them. Now we need to add the basic JavaHelp library to the project and add the code that calls into that library. To add the JavaHelp binary to the application:
jh.jar file in the javahelp2_0_04\jh2.0\javahelp\lib directory.
To add a method to the application that will open up your help set in the JavaHelp viewer:
Finally, it's time to hook the menu item to the openHelp() method.
openHelp() method:
contentsMenuItem.setAction(actionMap.get("openHelp")); // NOI18N
contentsMenuItem.setText(resourceMap.getString("contentsMenuItem.text")); // NOI18N
contentsMenuItem.setName("contentsMenuItem"); // NOI18N
fileMenu.add(contentsMenuItem);
At this point, you should be able to see your application and JavaHelp in action:
Here I've shown the most basic variant of adding a help set to your application. Another important aspect of this is setting up your application's build system to use JavaHelp. This will bring you the important benefits like the automatic creation of a search database and validating help metadata. If I'm not distracted by something more pressing and there's enough demand, I'll might cover these topics in ensuing posts. NetBeans Day - holy cow!Posted by pkeegan on June 27, 2005 at 05:56 PM | Permalink | Comments (0)I just finished up an article on NetBeans Day for the JavaOne Today, the conference's daily newsletter. It was fun trying to sound like a newspaper reporter, but now I want to reinsert my own voice into the proceedings, and I'll start with one word. Wow! There were the announcements (collaboration plugins, Matisse, new refactoring) and the stats (550 people or so attending according to Greg Sporar, who also has a recap). But beyond that I was impressed by how focused the attendees were. I figured that since it was a free event, there would be a lot of people popping their heads in and out. Easy come, easy go. But no. It was standing room only at the beginning and standing room only at the end. Check out some photos here. At one point, Tim Boudreau was talking in front of 150-200 people about plugin module development and digging into some API details. I cringed, figuring that most of the people there were IDE users and not particularly interested in adding to the IDE or building with the platform. I was waiting for the awkward mass exodus of people suddenly finding a need for a drink of water or a walk on Market St. But it never came. People stuck with him and had a ton of questions. I imagine the BOFs that the NetBeans team are doing at JavaOne will be similarly popular. I don't think anybody on the team was really prepared for the in-person developer response yesterday. At this time last year, 3.6 was the current release and we were just beginning to publicize and sell users on vast changes to the IDE's project workflow. Replacing the 3.x "filesystems" concept with the 4.x Ant-based project system was a big risk for us, but one we felt we needed to take to avoid sinking into irrelevance. People were curious about our new direction, but were taking a wait and see approach. Since then, we've seen a huge increase in our download numbers and some great press, which tells us that we're on the right track. But there is no more gratifying validation than seeing the excitement of real users in person. Our big little NetBeans IDE bookPosted by pkeegan on June 23, 2005 at 03:32 PM | Permalink | Comments (1)My name is Patrick Keegan. I've been a NetBeans IDE technical writer for the past six years. I'm starting this web log to communicate my impressions from JavaOne 2005 and I imagine I'll continue with it as long as I feel like I have something unique to say in this ever increasingly densely populated blogosphere. Today I'll start with a round of shameless self-promotion and get that out of the way. I'm coming to this year's JavaOne as co-author of the NetBeans IDE Field Guide. Pretty exciting for me personally and professionally and hopefully interesting for some of you as Java technology fans. If you're at the conference, stop by the Digital Guru stand to flip through a copy. Or come to NetBeans Day on Sunday and get a free copy (get there early!). I'll be at the Digital Guru stand Monday 4 - 4:30 p.m. with two of my co-authors - Ludovic Champenois and Charlie Hunt to sign copies and talk about the book. If you aren't coming to the conference, you can find it for a discount at Bookpool as well as other online vendors. When we started writing on the book, we wanted to include as much information as possible about the IDE. There's lots of documentation on the NetBeans project web site and we've gotten better at organizing and presenting it. But for many (like me) there's an undeniable pleasure about being able to leave the computer at the desk, flop down on a couch, flip open a book and start reading. (Also, since NetBeans is the premier everything in one package IDE, why not have a single book to reflect that.) That said, it's awfully hard to make a book comprehensive, comprehensible, *and* timely all at the same time. However, I think we've done a pretty good job in all three categories. The book delves deeply into the IDE's edit/compile/debug features and explores development of desktop, web, enterprise, and mobile apps. Timeliness is not the norm for such books when the target is constantly in motion as NetBeans IDE is, especially given the typical 3-4 month lag between submitting the manuscript and seeing the printed book. I'm proud of the fact that the Field Guide is coming out only a month after the 4.1 release and will remain relevant for a long time. More later. Hope to see you at JavaOne! | ||
|
|