按照教程,先把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 &copy; 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();
    }
}

 

posted on 2025-04-03 12:48  dalgleish  阅读(51)  评论(0)    收藏  举报