按照教程,先把spreadsheet的界面写好,书中是继承QMainWindow,但是我这里用的是QDialog,大家如果想继承到自己的UI中,可以继承QWidget。代码如下,不懂的请问AI或者认真跟着书一步一步写。其中有些地方,由于Qt版本不同,有些修改,但是不影响功能。
package jqt; import io.qt.core.*; import io.qt.gui.QAction; import io.qt.gui.QCloseEvent; import io.qt.gui.QIcon; import io.qt.gui.QKeySequence; import io.qt.widgets.*; public class Spreadsheet extends QDialog { //private variables private QSpreadsheet spreadsheet; private QMenuBar menuBar; private QToolBar toolBar; private QStatusBar statusBar; private FindDialog findDialog; private QLabel locationLabel, formulaLabel; private QStringList recentFiles; private String curFile; private final int MaxRecentFiles = 5; private QAction[] recentFileActions = new QAction[MaxRecentFiles]; private QAction separatorAction, newAction, openAction, saveAction, saveAsAction, exitAction, cutAction, copyAction, pasteAction, deleteAction, selectRowAction, selectColumnAction, selectAllAction, findAction, goToCellAction, recalculateAction, sortAction, showGridAction, autoRecalcAction, aboutAction, aboutQtAction; private QMenu fileMenu, editMenu, selectSubMenu, toolsMenu, optionsMenu, helpMenu; public Spreadsheet(){ this(null); } public Spreadsheet(QWidget parent){ super(parent); spreadsheet = new QSpreadsheet(); menuBar = new QMenuBar(); toolBar = new QToolBar(); toolBar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextUnderIcon); statusBar = new QStatusBar(); QVBoxLayout mainLayout = new QVBoxLayout(); mainLayout.addWidget(toolBar); mainLayout.addWidget(spreadsheet); mainLayout.addWidget(statusBar); mainLayout.setMenuBar(menuBar); setLayout(mainLayout); createActions(); createMenus(); createContextMenu(); createToolBars(); createStatusBar(); readSettings(); findDialog = null; setWindowIcon(new QIcon(":/toolbar/icon.png")); setWindowTitle("表格"); } //slots @Override protected void closeEvent(QCloseEvent event){ if (okToContinue()){ writeSettings(); event.accept(); } else event.ignore(); } private void newFile(){ if (okToContinue()){ spreadsheet.init(); setCurrentFile(""); } } private void openFile(){ if (okToContinue()){ QFileDialog.Result<String> fileName = QFileDialog.getOpenFileName(this, "打开表格", ".", "表格文件(*.sp);;所有文件(*.*)"); if (fileName != null && !fileName.result.isEmpty()) loadFile(fileName.result); } } private boolean save(){ if (curFile == null || curFile.isEmpty()) return saveAs(); return saveFile(curFile); } private boolean saveAs(){ QFileDialog.Result<String> fileName = QFileDialog.getSaveFileName(this, "保存表格", ".", "表格文件(*.sp);;所有文件(*.*)"); if (fileName == null || fileName.result.isEmpty()) return false; return saveFile(fileName.result); } private void find(){ if (findDialog == null){ findDialog = new FindDialog(this); findDialog.findNext.connect(spreadsheet, "findNext(String, CaseSensitivity)"); findDialog.findPrevious.connect(spreadsheet, "findPrevious(String, CaseSensitivity)"); } findDialog.show(); findDialog.raise(); findDialog.activateWindow(); } private void goToCell(){ GoToCellDialog goToCellDialog = new GoToCellDialog(this); if (goToCellDialog.exec() > 0){ String str = goToCellDialog.ui.lineEdit.text().toUpperCase(); spreadsheet.setCurrentCell(str.substring(1).toInt() - 1,str[0] - 'A'); } } private void sort(){ SortDialog sortDialog = new SortDialog(this); QTableWidgetSelectionRange range = spreadsheet.selectedRange(); sortDialog.setColumnRange((char) ('A' + range.leftColumn()), (char) ('A' + range.rightColumn())); if (sortDialog.exec() > 0) spreadsheet.sort(new SpreadsheetComparator(sortDialog)); } private void about(){ QMessageBox.about(this, "关于表格", "<h2>Spreadsheet 1.1</h2>\n" + "<p>Copyright © 2025 One.\n" + "<p>Spreadsheet is a small application that " + "demonstrates QAction, QMainWindow, QMenuBar" + "QStatusBar, QTableWidget, QToolBar, and many other" + "Qt classes."); } private void openRecentFile(){ if (okToContinue()){ QAction action = QObject.qobject_cast(QAction.class, sender()); if (action != null) loadFile(action.data().toString()); } } private void updateStatusBar(){ locationLabel.setText(spreadsheet.currentLocation()); formulaLabel.setText(spreadsheet.currentFormula()); } private void spreadsheetModified(){ setWindowModified(true); updateStatusBar(); } //private methods private void createActions(){ newAction = new QAction("新建(&N)"); newAction.setIcon(new QIcon(":/toolbar/new.png")); newAction.setShortcut(QKeySequence.StandardKey.New); newAction.setStatusTip("新建表格文件"); newAction.triggered.connect(this::newFile); openAction = new QAction("打开(&O)"); openAction.setIcon(new QIcon(":/toolbar/open.png")); openAction.setShortcut(QKeySequence.StandardKey.Open); openAction.setStatusTip("打开表格文件"); openAction.triggered.connect(this::openFile); saveAction = new QAction("保存(&S)"); saveAction.setIcon(new QIcon(":/toolbar/save.png")); saveAction.setShortcut(QKeySequence.StandardKey.Save); saveAction.setStatusTip("保存表格文件"); saveAction.triggered.connect(this::save); saveAsAction = new QAction("另存为(&A)"); saveAsAction.setStatusTip("另存表格文件至"); saveAsAction.triggered.connect(this::saveAs); for (int i = 0; i < MaxRecentFiles; i++){ recentFileActions[i] = new QAction(); recentFileActions[i].setVisible(false); recentFileActions[i].triggered.connect(this::openRecentFile); } exitAction = new QAction("退出(&E)"); exitAction.setShortcut("Ctrl+Q"); exitAction.setStatusTip("退出当前程序"); exitAction.triggered.connect(this::close); cutAction = new QAction("剪切(&X)"); cutAction.setIcon(new QIcon(":/toolbar/cut.png")); cutAction.setShortcut(QKeySequence.StandardKey.Cut); cutAction.setStatusTip("剪切单元格"); cutAction.triggered.connect(spreadsheet, "cut()"); copyAction = new QAction("复制(&C)"); copyAction.setIcon(new QIcon(":/toolbar/copy.png")); copyAction.setShortcut(QKeySequence.StandardKey.Copy); copyAction.setStatusTip("复制单元格"); copyAction.triggered.connect(spreadsheet, "copy()"); pasteAction = new QAction("粘贴(&V)"); pasteAction.setIcon(new QIcon(":/toolbar/paste.png")); pasteAction.setShortcut(QKeySequence.StandardKey.Paste); pasteAction.setStatusTip("粘贴单元格"); pasteAction.triggered.connect(spreadsheet, "paste()"); deleteAction = new QAction("删除(&D)"); deleteAction.setShortcut(QKeySequence.StandardKey.Delete); deleteAction.setStatusTip("删除单元格"); deleteAction.triggered.connect(spreadsheet,"del()"); selectRowAction = new QAction("选择行(&R)"); selectRowAction.setStatusTip("选择行所在的所有单元格"); selectRowAction.triggered.connect(spreadsheet, "selectCurrentRow()"); selectColumnAction = new QAction("选择列(&C)"); selectColumnAction.setStatusTip("选择列所在的所有单元格"); selectColumnAction.triggered.connect(spreadsheet, "selectCurrentColumn()"); selectAllAction = new QAction("选择所有(&A)"); selectAllAction.setShortcut(QKeySequence.StandardKey.SelectAll); selectAllAction.setStatusTip("选择所有单元格"); selectAllAction.triggered.connect(spreadsheet::selectAll); findAction = new QAction("搜索(&F)"); findAction.setIcon(new QIcon(":/toolbar/find.png")); findAction.setShortcut(QKeySequence.StandardKey.Find); findAction.setStatusTip("查找单元格"); findAction.triggered.connect(this::find); goToCellAction = new QAction("跳到(&G)"); goToCellAction.setIcon(new QIcon(":/toolbar/goToCell.png")); goToCellAction.setShortcut("Ctrl+G"); goToCellAction.setStatusTip("跳到指定单元格"); goToCellAction.triggered.connect(this::goToCell); recalculateAction = new QAction("重计算"); recalculateAction.setShortcut("F9"); recalculateAction.setStatusTip("重计算所有单元格数据"); recalculateAction.triggered.connect(spreadsheet, "recalculate()"); sortAction = new QAction("排序(&S)"); sortAction.setStatusTip("重排序单元格"); sortAction.triggered.connect(this::sort); showGridAction = new QAction("显示网格(&S)"); showGridAction.setCheckable(true); showGridAction.setChecked(spreadsheet.showGrid()); showGridAction.setStatusTip("显示表格网格"); showGridAction.toggled.connect(spreadsheet::setShowGrid); autoRecalcAction = new QAction("自动计算(&A)"); autoRecalcAction.setCheckable(true); autoRecalcAction.setChecked(spreadsheet.autoRecal()); autoRecalcAction.setStatusTip("启动自动计算"); autoRecalcAction.toggled.connect(spreadsheet, "setAutoRecal(boolean)"); aboutAction = new QAction("关于(&A)"); aboutAction.setStatusTip("应用程序简介"); aboutAction.triggered.connect(this::about); aboutQtAction = new QAction("关于QT(&Q)"); aboutQtAction.setStatusTip("Qt程序简介"); aboutQtAction.triggered.connect(QApplication::aboutQt); } private void createMenus(){ fileMenu = menuBar.addMenu("文件(&F)"); fileMenu.addAction(newAction); fileMenu.addAction(openAction); fileMenu.addAction(saveAction); fileMenu.addAction(saveAsAction); separatorAction = fileMenu.addSeparator(); for (int i = 0; i < MaxRecentFiles; i++) fileMenu.addAction(recentFileActions[i]); fileMenu.addSeparator(); fileMenu.addAction(exitAction); editMenu = menuBar.addMenu("编辑(&E)"); editMenu.addAction(cutAction); editMenu.addAction(copyAction); editMenu.addAction(pasteAction); editMenu.addAction(deleteAction); selectSubMenu = editMenu.addMenu("选择(&S)"); selectSubMenu.addAction(selectRowAction); selectSubMenu.addAction(selectColumnAction); selectSubMenu.addAction(selectAllAction); editMenu.addSeparator(); editMenu.addAction(findAction); editMenu.addAction(goToCellAction); toolsMenu = menuBar.addMenu("工具(&T)"); toolsMenu.addAction(recalculateAction); toolsMenu.addAction(sortAction); optionsMenu = menuBar.addMenu("选项(&O)"); optionsMenu.addAction(showGridAction); optionsMenu.addAction(autoRecalcAction); menuBar.addSeparator(); helpMenu = menuBar.addMenu("帮助(&H)"); helpMenu.addAction(aboutAction); helpMenu.addAction(aboutQtAction); } private void createContextMenu(){ spreadsheet.addAction(cutAction); spreadsheet.addAction(copyAction); spreadsheet.addAction(pasteAction); spreadsheet.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu); } private void createToolBars(){ toolBar.addAction(newAction); toolBar.addAction(openAction); toolBar.addAction(saveAction); toolBar.addAction(cutAction); toolBar.addAction(copyAction); toolBar.addAction(pasteAction); toolBar.addSeparator(); toolBar.addAction(findAction); toolBar.addAction(goToCellAction); } private void createStatusBar(){ locationLabel = new QLabel("W999"); locationLabel.setAlignment(Qt.AlignmentFlag.AlignHCenter); locationLabel.setMinimumSize(locationLabel.sizeHint()); formulaLabel = new QLabel(); formulaLabel.setIndent(3); statusBar.addWidget(locationLabel); statusBar.addWidget(formulaLabel, 1); spreadsheet.currentCellChanged.connect(this::updateStatusBar); spreadsheet.modified.connect(this::spreadsheetModified); updateStatusBar(); } private void readSettings(){ QSettings settings = new QSettings("Spreadsheet.ini", QSettings.Format.IniFormat); restoreGeometry(settings.value("geometry").toValue(QByteArray.class)); recentFiles = settings.value("recentFiles").toValue(QStringList.class); if (!recentFiles.isEmpty()) updateRecentFileActions(); boolean showGrid = settings.value("showGrid").toBoolean(); showGridAction.setChecked(showGrid); boolean autoRecalc = settings.value("autoRecalc", false).toBoolean(); autoRecalcAction.setChecked(autoRecalc); } private void writeSettings(){ QSettings settings = new QSettings("Spreadsheet.ini", QSettings.Format.IniFormat); settings.setValue("geometry", saveGeometry()); settings.setValue("recentFiles", recentFiles); settings.setValue("showGrid", showGridAction.isChecked()); settings.setValue("autoRecalc", autoRecalcAction.isChecked()); } private boolean okToContinue(){ if (isWindowModified()){ QMessageBox.StandardButton r = QMessageBox.warning(this,"表格","内容已变动,是否保存?", new QMessageBox.StandardButtons(QMessageBox.StandardButton.Yes, QMessageBox.StandardButton.No, QMessageBox.StandardButton.Cancel)); if (r == QMessageBox.StandardButton.Yes) return save(); else if (r == QMessageBox.StandardButton.Cancel) return false; } return true; } private boolean loadFile(String fileName){ if (!spreadsheet.readFile(fileName)){ statusBar.showMessage("表格加载中断", 2000); return false; } setCurrentFile(fileName); statusBar.showMessage("表格加载成功", 2000); return true; } private boolean saveFile(String fileName){ if (!spreadsheet.writeFile(fileName)){ statusBar.showMessage("表格保存中断", 2000); return false; } setCurrentFile(fileName); statusBar.showMessage("表格保存成功", 2000); return true; } private void setCurrentFile(String fileName){ curFile = fileName; setWindowModified(false); String showName = "未命名"; if (!curFile.isEmpty()){ showName = strippedName(curFile); recentFiles.removeAll(curFile); recentFiles.prepend(curFile); updateRecentFileActions(); } setWindowTitle(String.format("%s[*] - %s", showName, "表格")); } private void updateRecentFileActions(){ for (String str : recentFiles){ if (!QFile.exists(str)) recentFiles.remove(str); } for (int j = 0; j < MaxRecentFiles; j++){ if (j < recentFiles.count()){ String text = "%1".arg(strippedName(recentFiles.get(j))); recentFileActions[j].setText(text); recentFileActions[j].setData(recentFiles.get(j)); recentFileActions[j].setVisible(true); } else recentFileActions[j].setVisible(false); } separatorAction.setVisible(!recentFiles.isEmpty()); } private String strippedName(String fullFileName){ return new QFileInfo(fullFileName).fileName(); } }
浙公网安备 33010602011771号