D越来越有玩头了~~
感觉一下代码的流畅:
1 module main; 2 3 /** 4 * Imports. 5 */ 6 import std.algorithm; 7 import std.array; 8 import std.datetime; 9 import std.file; 10 import tkd.tkdapplication; 11 12 /** 13 * Sample application. 14 */ 15 class Application : TkdApplication 16 { 17 /** 18 * Widgets we need access to on the class level. 19 */ 20 private Entry _entry; 21 private ProgressBar _progressBar; 22 private Canvas _canvas; 23 private Entry _fontEntry; 24 private Entry _colorEntry; 25 private Entry _directoryEntry; 26 private Entry _openFileEntry; 27 private Entry _saveFileEntry; 28 private Entry _messageEntry; 29 30 /** 31 * Open the font dialog. 32 * 33 * Params: 34 * args = The callback args. 35 */ 36 private void openFontDialog(CommandArgs args) 37 { 38 auto dialog = new FontDialog("Choose a font") 39 .setCommand(delegate(CommandArgs args){ 40 this._fontEntry.setValue(args.dialog.font); 41 }) 42 .show(); 43 } 44 45 /** 46 * Open the color dialog. 47 * 48 * Params: 49 * args = The callback args. 50 */ 51 private void openColorDialog(CommandArgs args) 52 { 53 auto dialog = new ColorDialog("Choose a color") 54 .setInitialColor(Color.beige) 55 .show(); 56 this._colorEntry.setValue(dialog.getResult()); 57 } 58 59 /** 60 * Open the directory dialog. 61 * 62 * Params: 63 * args = The callback args. 64 */ 65 private void openDirectoryDialog(CommandArgs args) 66 { 67 auto dialog = new DirectoryDialog("Choose a directory") 68 .setDirectoryMustExist(true) 69 .show(); 70 this._directoryEntry.setValue(dialog.getResult()); 71 } 72 73 /** 74 * Open the open file dialog. 75 * 76 * Params: 77 * args = The callback args. 78 */ 79 private void openOpenFileDialog(CommandArgs args) 80 { 81 auto dialog = new OpenFileDialog() 82 .setMultiSelection(true) 83 .setDefaultExtension(".dmo") 84 .addFileType("{{All files} {*}}") 85 .addFileType("{{D language files} {.d .di}}") 86 .addFileType("{{HTML files} {.htm .html}}") 87 .addFileType("{{Text files} {.txt}}") 88 .setInitialDirectory("~") 89 .setInitialFile("file-to-open.dmo") 90 .show(); 91 this._openFileEntry.setValue(dialog.getResults().join(" ")); 92 } 93 94 /** 95 * Open the save file dialog. 96 * 97 * Params: 98 * args = The callback args. 99 */ 100 private void openSaveFileDialog(CommandArgs args) 101 { 102 auto dialog = new SaveFileDialog() 103 .setConfirmOverwrite(true) 104 .setDefaultExtension(".dmo") 105 .addFileType("{{All files} {*}}") 106 .addFileType("{{D language files} {.d .di}}") 107 .addFileType("{{HTML files} {.htm .html}}") 108 .addFileType("{{Text files} {.txt}}") 109 .setInitialDirectory("~") 110 .setInitialFile("file-to-save.dmo") 111 .show(); 112 this._saveFileEntry.setValue(dialog.getResult()); 113 } 114 115 /** 116 * Open the message dialog. 117 * 118 * Params: 119 * args = The callback args. 120 */ 121 private void openMessageDialog(CommandArgs args) 122 { 123 auto dialog = new MessageDialog() 124 .setMessage("Lorem ipsum dolor sit amet.") 125 .setDetailMessage("Nunc at aliquam arcu. Sed eget tellus ligula. Sed egestas est et tempus cursus.") 126 .setType(MessageDialogType.okcancel) 127 .show(); 128 this._messageEntry.setValue(dialog.getResult()); 129 } 130 131 /** 132 * Mark a point in the canvas to drag from. 133 * 134 * Params: 135 * args = The callback args. 136 */ 137 private void mark(CommandArgs args) 138 { 139 this._canvas.setScanMark(args.event.x, args.event.y); 140 } 141 142 /** 143 * Drag the canvas to reposition the contents. 144 * 145 * Params: 146 * args = The callback args. 147 */ 148 private void drag(CommandArgs args) 149 { 150 this._canvas.scanDragTo(args.event.x, args.event.y); 151 } 152 153 /** 154 * Show the about box. 155 */ 156 private void showAbout(CommandArgs args) 157 { 158 auto dialog = new MessageDialog("About") 159 .setMessage("Tkd Showcase") 160 .setDetailMessage("An showcase Tkd application demonstrating menus, widgets and dialogs. The possiblities are endless.") 161 .show(); 162 } 163 164 /** 165 * Create the menu. 166 */ 167 private void createMenu() 168 { 169 auto menuBar = new MenuBar(this.mainWindow); 170 171 auto fileMenu = new Menu(menuBar, "File", 0) 172 .addEntry(new EmbeddedPng!("cancel.png"), "Quit", &this.exitApplication, ImagePosition.left, "Ctrl-Q"); 173 174 auto helpMenu = new Menu(menuBar, "Help", 0) 175 .addEntry(new EmbeddedPng!("help.png"), "About...", &this.showAbout, ImagePosition.left, "F1"); 176 } 177 178 /** 179 * Create the widget pane for the note book. 180 * 181 * Returns: 182 * The widget pane. 183 */ 184 private Frame createWidgetPane() 185 { 186 auto widgetPane = new Frame(); 187 188 auto entryLabelFrame = new LabelFrame(widgetPane, "Text Entry") 189 .pack(10, 0, GeometrySide.top, GeometryFill.both, AnchorPosition.center, true); 190 auto entry1 = new Text(entryLabelFrame) 191 .setWidth(0) 192 .setHeight(3) 193 .appendText("Nullam sapien lectus, aliquet sit amet quam et, sagittis porttitor dolor.") 194 .pack(5, 0, GeometrySide.bottom, GeometryFill.both, AnchorPosition.northWest, true); 195 this._entry = new Entry(entryLabelFrame) 196 .pack(5, 0, GeometrySide.left, GeometryFill.x, AnchorPosition.northWest, true); 197 auto entry3 = new SpinBox(entryLabelFrame) 198 .setData(["foo", "bar", "baz", "qux"]) 199 .setWrap(true) 200 .setWidth(5) 201 .pack(5, 0, GeometrySide.left); 202 auto entry4 = new ComboBox(entryLabelFrame) 203 .setData(["Option 1", "Option 2", "Option 3"]) 204 .setValue("Option 1") 205 .pack(5, 0, GeometrySide.left, GeometryFill.x, AnchorPosition.northWest, true); 206 207 auto rangeLabelFrame = new LabelFrame(widgetPane, "Progress & Scale") 208 .pack(10, 0, GeometrySide.bottom, GeometryFill.both, AnchorPosition.center); 209 this._progressBar = new ProgressBar(rangeLabelFrame) 210 .setMaxValue(10) 211 .setValue(4) 212 .pack(5, 0, GeometrySide.top, GeometryFill.x, AnchorPosition.center, true); 213 auto scale = new Scale(rangeLabelFrame) 214 .setFromValue(10) 215 .setToValue(0) 216 .setCommand(delegate(CommandArgs args){ 217 auto scale = cast(Scale)args.element; 218 this._progressBar.setValue(scale.getValue()); 219 }) 220 .setValue(4) 221 .pack(5, 0, GeometrySide.top, GeometryFill.x, AnchorPosition.center, true); 222 223 auto buttonLabelFrame = new LabelFrame(widgetPane, "Buttons") 224 .pack(10, 0, GeometrySide.left, GeometryFill.both, AnchorPosition.center, true); 225 auto button1 = new Button(buttonLabelFrame, "Text button") 226 .pack(5); 227 auto button2 = new Button(buttonLabelFrame, new EmbeddedPng!("thumbnail.png"), "Image button", ImagePosition.left) 228 .pack(5); 229 auto buttonMenu = new Menu() 230 .addEntry("Option 1", delegate(CommandArgs args){}) 231 .addEntry("Option 2", delegate(CommandArgs args){}) 232 .addEntry("Option 3", delegate(CommandArgs args){}); 233 auto button3 = new MenuButton(buttonLabelFrame, "Menu button", buttonMenu) 234 .pack(5); 235 236 auto checkBoxLabelFrame = new LabelFrame(widgetPane, "Check buttons") 237 .pack(10, 0, GeometrySide.left, GeometryFill.both, AnchorPosition.center, true); 238 auto checkButton1 = new CheckButton(checkBoxLabelFrame, "Option 1") 239 .check() 240 .pack(5); 241 auto checkButton2 = new CheckButton(checkBoxLabelFrame, "Option 2") 242 .pack(5); 243 auto checkButton3 = new CheckButton(checkBoxLabelFrame, "Option 3") 244 .pack(5); 245 246 auto radioLabelFrame = new LabelFrame(widgetPane, "Radio buttons") 247 .pack(10, 0, GeometrySide.left, GeometryFill.both, AnchorPosition.center, true); 248 auto radioButton1 = new RadioButton(radioLabelFrame, "Option 1") 249 .setSelectedValue("1") 250 .select() 251 .pack(5); 252 auto radioButton2 = new RadioButton(radioLabelFrame, "Option 2") 253 .setSelectedValue("2") 254 .pack(5); 255 auto radioButton3 = new RadioButton(radioLabelFrame, "Option 3") 256 .setSelectedValue("3") 257 .pack(5); 258 259 return widgetPane; 260 } 261 262 /** 263 * Create the paned pane for the note book. 264 * 265 * Returns: 266 * The paned pane. 267 */ 268 private Frame createPanedPane() 269 { 270 auto panedPane = new Frame(); 271 272 auto panedWindow = new PanedWindow(panedPane); 273 274 auto rows = new TreeViewRow(["Computer"], true, ["computer"]); 275 rows.children ~= new TreeViewRow(["Documents"], true, ["folder"]); 276 rows.children[0].children ~= new TreeViewRow(["Important notes.txt"], true, ["file"]); 277 rows.children[0].children ~= new TreeViewRow(["The D Programming Language.pdf"], true, ["pdf"]); 278 rows.children ~= new TreeViewRow(["Pictures"], true, ["folder"]); 279 rows.children[1].children ~= new TreeViewRow(["Gary and Tessa.jpg"], true, ["image"]); 280 rows.children ~= new TreeViewRow(["Videos"], true, ["folder"]); 281 rows.children[2].children ~= new TreeViewRow(["Carlito's Way (1993).mpg"], true, ["video"]); 282 rows.children[2].children ~= new TreeViewRow(["Aliens (1986).mpg"], true, ["video"]); 283 284 auto tree1 = new TreeView(panedWindow) 285 .setHeading("Directory listing") 286 .setTag("computer", new EmbeddedPng!("computer.png")) 287 .setTag("folder", new EmbeddedPng!("folder.png")) 288 .setTag("file", new EmbeddedPng!("page.png")) 289 .setTag("pdf", new EmbeddedPng!("page_white_acrobat.png")) 290 .setTag("video", new EmbeddedPng!("film.png")) 291 .setTag("image", new EmbeddedPng!("images.png")) 292 .addRow(rows); 293 294 auto tree2 = new TreeView(panedWindow) 295 .setHeading("Film") 296 .setWidth(250) 297 .addColumn(new TreeViewColumn("Year").setWidth(20)) 298 .addColumn(new TreeViewColumn("IMDB ranking").setWidth(50)) 299 .addRow(new TreeViewRow(["The Shawshank Redemption", "1994", "1"])) 300 .addRow(new TreeViewRow(["The Godfather", "1972", "2"])) 301 .addRow(new TreeViewRow(["The Godfather: Part II", "1974", "3"])) 302 .addRow(new TreeViewRow(["The Dark Knight", "2008", "4"])) 303 .addRow(new TreeViewRow(["Pulp Fiction", "1994", "5"])) 304 .addRow(new TreeViewRow(["The Good, the Bad and the Ugly", "1966", "6"])) 305 .addRow(new TreeViewRow(["Schindler's List", "1993", "7"])) 306 .addRow(new TreeViewRow(["Angry Men", "1957", "8"])) 307 .addRow(new TreeViewRow(["The Lord of the Rings: The Return of the King", "2003", "9"])) 308 .addRow(new TreeViewRow(["Fight Club", "1999", "10"])); 309 310 panedWindow 311 .addPane(tree1).setPaneWeight(0, 1) 312 .addPane(tree2).setPaneWeight(1, 1) 313 .pack(10, 0, GeometrySide.top, GeometryFill.both, AnchorPosition.center, true); 314 315 return panedPane; 316 } 317 318 /** 319 * Create the canvas pane for the note book. 320 * 321 * Returns: 322 * The canvas pane. 323 */ 324 private Frame createCanvasPane() 325 { 326 auto canvasPane = new Frame(); 327 328 auto container = new Frame(canvasPane) 329 .pack(10, 0, GeometrySide.top, GeometryFill.both, AnchorPosition.center, true); 330 331 container.configureGeometryColumn(0, 1); 332 container.configureGeometryRow(0, 1); 333 334 this._canvas = new Canvas(container, Color.bisque) 335 .setCursor(Cursor.hand1) 336 .setScrollRegion(-300, -250, 610, 500) 337 .addItem(new CanvasRectangle([10, 10, 200, 100]).addTag("tagged")) 338 .addItem(new CanvasArc([10, 110, 110, 210], CanvasArcStyle.pie, Color.paleGreen)) 339 .addItem(new CanvasImage([210, 10], new EmbeddedPng!("thumbnail.png"))) 340 .addItem(new CanvasImage([260, 10], new EmbeddedGif!("thumbnail.gif"))) 341 .addItem(new CanvasLine([120, 110, 200, 110, 200, 160]).setArrowPosition(CanvasLineArrow.last)) 342 .addItem(new CanvasOval([10, 170, 200, 245], Color.rosyBrown3)) 343 .addItem(new CanvasPolygon([220, 80, 320, 80, 300, 120, 240, 120], Color.mediumPurple)) 344 .addItem(new CanvasText([30, 192], "Tkd Canvas", Color.white).setFont("{Times New Roman} 22 bold")) 345 .addItem(new CanvasWidget([220, 140], new Button("Embedded Widget", new EmbeddedPng!("error.png"))).setWidth(100).setHeight(100)) 346 .addTagConfig(new CanvasTagConfig("tagged").setFillColor(Color.salmon)) 347 .setXView(0.25) 348 .setYView(0.24) 349 .bind("<ButtonPress-1>", &this.mark) 350 .bind("<B1-Motion>", &this.drag); 351 352 auto xscroll = new XScrollBar(container) 353 .attachWidget(this._canvas) 354 .grid(0, 1, 0, 0, 1, 1, "esw"); 355 356 auto yscroll = new YScrollBar(container) 357 .attachWidget(this._canvas) 358 .grid(1, 0, 0, 0, 1, 1, "nes"); 359 360 this._canvas 361 .attachXScrollBar(xscroll) 362 .attachYScrollBar(yscroll) 363 .grid(0, 0, 0, 0, 1, 1, "nesw"); 364 365 return canvasPane; 366 } 367 368 /** 369 * Create the dialog pane for the note book. 370 * 371 * Returns: 372 * The dialog pane. 373 */ 374 private Frame createDialogPane() 375 { 376 auto dialogPane = new Frame(); 377 378 auto modalLabelFrame = new LabelFrame(dialogPane, "Modal") 379 .configureGeometryColumn(1, 1) 380 .pack(10, 0, GeometrySide.top, GeometryFill.both, AnchorPosition.center, true); 381 382 auto colorButton = new Button(modalLabelFrame, new EmbeddedPng!("color_swatch.png"), "Color", ImagePosition.left) 383 .setCommand(&this.openColorDialog) 384 .grid(0, 0, 10); 385 386 this._colorEntry = new Entry(modalLabelFrame) 387 .grid(1, 0, 10, 0, 1, 1, "ew"); 388 389 auto directoryButton = new Button(modalLabelFrame, new EmbeddedPng!("chart_organisation.png"), "Directory", ImagePosition.left) 390 .setCommand(&this.openDirectoryDialog) 391 .grid(0, 1, 10); 392 393 this._directoryEntry = new Entry(modalLabelFrame) 394 .setWidth(40) 395 .grid(1, 1, 10, 0, 1, 1, "ew"); 396 397 auto fileOpenButton = new Button(modalLabelFrame, new EmbeddedPng!("folder_page.png"), "Open File", ImagePosition.left) 398 .setCommand(&this.openOpenFileDialog) 399 .grid(0, 2, 10); 400 401 this._openFileEntry = new Entry(modalLabelFrame) 402 .setWidth(40) 403 .grid(1, 2, 10, 0, 1, 1, "ew"); 404 405 auto fileSaveButton = new Button(modalLabelFrame, new EmbeddedPng!("disk.png"), "Save File", ImagePosition.left) 406 .setCommand(&this.openSaveFileDialog) 407 .grid(0, 3, 10); 408 409 this._saveFileEntry = new Entry(modalLabelFrame) 410 .setWidth(40) 411 .grid(1, 3, 10, 0, 1, 1, "ew"); 412 413 auto messageButton = new Button(modalLabelFrame, new EmbeddedPng!("comment.png"), "Message", ImagePosition.left) 414 .setCommand(&this.openMessageDialog) 415 .grid(0, 4, 10); 416 417 this._messageEntry = new Entry(modalLabelFrame) 418 .setWidth(40) 419 .grid(1, 4, 10, 0, 1, 1, "ew"); 420 421 auto nonModalLabelFrame = new LabelFrame(dialogPane, "Non Modal") 422 .configureGeometryColumn(1, 1) 423 .pack(10, 0, GeometrySide.top, GeometryFill.both, AnchorPosition.center, true); 424 425 auto fontButton = new Button(nonModalLabelFrame, new EmbeddedPng!("style.png"), "Font", ImagePosition.left) 426 .setCommand(&this.openFontDialog) 427 .grid(0, 0, 10); 428 429 this._fontEntry = new Entry(nonModalLabelFrame) 430 .setWidth(40) 431 .grid(1, 0, 10, 0, 1, 1, "ew"); 432 433 return dialogPane; 434 } 435 436 /** 437 * Set up the key bindings for the application. 438 */ 439 private void setUpKeyBindings() 440 { 441 this.mainWindow.bind("<F1>", &this.showAbout); 442 this.mainWindow.bind("<Control-q>", &this.exitApplication); 443 } 444 445 /** 446 * Initialise the user interface. 447 */ 448 override protected void initInterface() 449 { 450 this.mainWindow.setTitle("Tkd Showcase"); 451 this.mainWindow.setMinSize(550, 560); 452 this.mainWindow.setDefaultIcon([new EmbeddedPng!("tkicon.png")]); 453 454 this.mainWindow.setProtocolCommand(WindowProtocol.deleteWindow, delegate(CommandArgs args){ 455 this.showAbout(args); 456 this.exitApplication(args); 457 }); 458 459 this.mainWindow.setIdleCommand(delegate(CommandArgs args){ 460 this._entry.setValue(Clock.currTime().toLocalTime().toSimpleString().findSplitBefore(".")[0]); 461 this.mainWindow.setIdleCommand(args.callback, 1000); 462 }); 463 464 this.createMenu(); 465 466 auto noteBook = new NoteBook(); 467 auto widgetPane = this.createWidgetPane(); 468 auto panedPane = this.createPanedPane(); 469 auto canvasPane = this.createCanvasPane(); 470 auto dialogPane = this.createDialogPane(); 471 472 noteBook 473 .addTab("Widgets", widgetPane).setTabImage(0, new EmbeddedPng!("layout_content.png"), ImagePosition.left) 474 .addTab("Panes", panedPane).setTabImage(1, new EmbeddedPng!("application_tile_horizontal.png"), ImagePosition.left) 475 .addTab("Canvas", canvasPane).setTabImage(2, new EmbeddedPng!("shape_ungroup.png"), ImagePosition.left) 476 .addTab("Dialogs", dialogPane).setTabImage(3, new EmbeddedPng!("application_double.png"), ImagePosition.left) 477 .pack(10, 0, GeometrySide.top, GeometryFill.both, AnchorPosition.center, true); 478 479 auto exitButton = new Button("Exit") 480 .setCommand(&this.exitApplication) 481 .pack(5); 482 483 auto sizeGrip = new SizeGrip(this.mainWindow) 484 .pack(0, 0, GeometrySide.bottom, GeometryFill.none, AnchorPosition.southEast); 485 486 this.setUpKeyBindings(); 487 } 488 489 /** 490 * Exit the application. 491 * 492 * Params: 493 * args = The command arguments. 494 */ 495 private void exitApplication(CommandArgs args) 496 { 497 this.exit(); 498 } 499 500 } 501 502 /** 503 * Main entry point. 504 * 505 * Params: 506 * args = An array of command line arguments passed to this program. 507 */ 508 void main(string[] args) 509 { 510 auto app = new Application(); 511 app.run(); 512 }