12.8Java Swing 中的MVC

在 Java Swing 中,MVC 模式被广泛应用。例如,JTable、JList 等组件都采用了这种模式。通常:

  • 模型:实现特定的 Swing 模型接口(如 TableModel、ListModel)。
  • 视图:是 Swing 组件本身(如 JTable、JList)。
  • 控制器:通常隐含在组件内部,或由开发者实现为事件监听器。

JTableModel 是 Java Swing 中用于管理表格数据的核心接口,它是 MVC(Model-View-Controller)模式在表格组件中的具体实现。JTable 作为视图,负责显示数据;而 JTableModel 作为模型,负责存储和管理数据,并提供数据访问接口。

JTableModel 接口方法

JTableModel 接口定义了以下核心方法:

  1. 基本结构方法

    • int getRowCount():返回表格的行数
    • int getColumnCount():返回表格的列数
    • String getColumnName(int columnIndex):返回指定列的名称
    • Class<?> getColumnClass(int columnIndex):返回指定列的数据类型
  2. 数据访问方法

    • Object getValueAt(int rowIndex, int columnIndex):获取指定单元格的数据
    • void setValueAt(Object aValue, int rowIndex, int columnIndex):设置指定单元格的数据
  3. 可选方法

    • boolean isCellEditable(int rowIndex, int columnIndex):指定单元格是否可编辑

实现方式

JTableModel 有三种主要实现方式:

  1. DefaultTableModel

    • 最简单的实现,使用 Vector 存储数据和列名
    • 缺点:所有单元格数据类型被视为 Object,不支持类型安全
  2. AbstractTableModel

    • 抽象基类,提供了事件通知机制
    • 通常继承此类并实现必要的方法
  3. 自定义 TableModel

    • 完全自定义实现,适用于复杂数据结构和特殊需求

案例:自定义 TableModel 实现

下面通过一个案例展示如何实现自定义 TableModel:

Main.java

import javax.swing.*;
import java.awt.*;public class Main {public static void main(String[] args) {SwingUtilities.invokeLater(() -> {// 创建主窗口JFrame frame = new JFrame("人员信息管理");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setSize(500, 300);frame.setLocationRelativeTo(null);// 创建自定义TableModelPersonTableModel model = new PersonTableModel();// 添加示例数据model.addPerson(new Person("张三", 25, false));model.addPerson(new Person("李四", 30, true));model.addPerson(new Person("王五", 22, false));// 创建表格并关联TableModelJTable table = new JTable(model);// 添加表格到滚动面板JScrollPane scrollPane = new JScrollPane(table);// 添加按钮面板JPanel buttonPanel = new JPanel();JButton addButton = new JButton("添加");JButton deleteButton = new JButton("删除");// 添加按钮事件处理addButton.addActionListener(e -> {String name = JOptionPane.showInputDialog(frame, "请输入姓名:");if (name != null && !name.isEmpty()) {String ageStr = JOptionPane.showInputDialog(frame, "请输入年龄:");if (ageStr != null && !ageStr.isEmpty()) {try {int age = Integer.parseInt(ageStr);String marriedStr = JOptionPane.showInputDialog(frame, "是否已婚(true/false):");boolean married = Boolean.parseBoolean(marriedStr);model.addPerson(new Person(name, age, married));} catch (NumberFormatException ex) {JOptionPane.showMessageDialog(frame, "年龄必须是数字!");}}}});deleteButton.addActionListener(e -> {int selectedRow = table.getSelectedRow();if (selectedRow != -1) {model.deletePerson(selectedRow);} else {JOptionPane.showMessageDialog(frame, "请先选择一行!");}});buttonPanel.add(addButton);buttonPanel.add(deleteButton);// 添加组件到窗口frame.getContentPane().add(scrollPane, BorderLayout.CENTER);frame.getContentPane().add(buttonPanel, BorderLayout.SOUTH);// 显示窗口frame.setVisible(true);});}
}    

PersonTableModel.java 

import javax.swing.table.AbstractTableModel;
import java.util.ArrayList;
import java.util.List;// 人员类,存储表格中的一行数据
class Person {private String name;private int age;private boolean married;public Person(String name, int age, boolean married) {this.name = name;this.age = age;this.married = married;}public String getName() { return name; }public int getAge() { return age; }public boolean isMarried() { return married; }public void setName(String name) { this.name = name; }public void setAge(int age) { this.age = age; }public void setMarried(boolean married) { this.married = married; }
}// 自定义TableModel实现
public class PersonTableModel extends AbstractTableModel {private static final long serialVersionUID = 1L;// 列名数组private final String[] columnNames = {"姓名", "年龄", "已婚"};// 列数据类型数组private final Class<?>[] columnTypes = {String.class, Integer.class, Boolean.class};// 数据列表private final List<Person> data = new ArrayList<>();// 添加人员数据public void addPerson(Person person) {data.add(person);// 通知表格数据已插入fireTableRowsInserted(data.size() - 1, data.size() - 1);}// 更新人员数据public void updatePerson(int row, Person person) {data.set(row, person);// 通知表格数据已更新fireTableRowsUpdated(row, row);}// 删除人员数据public void deletePerson(int row) {data.remove(row);// 通知表格数据已删除fireTableRowsDeleted(row, row);}// 获取指定行的人员数据public Person getPerson(int row) {return data.get(row);}// 返回表格行数@Overridepublic int getRowCount() {return data.size();}// 返回表格列数@Overridepublic int getColumnCount() {return columnNames.length;}// 返回列名@Overridepublic String getColumnName(int column) {return columnNames[column];}// 返回列数据类型@Overridepublic Class<?> getColumnClass(int columnIndex) {return columnTypes[columnIndex];}// 返回单元格数据@Overridepublic Object getValueAt(int rowIndex, int columnIndex) {Person person = data.get(rowIndex);switch (columnIndex) {case 0: return person.getName();case 1: return person.getAge();case 2: return person.isMarried();default: return null;}}// 设置单元格数据并使单元格可编辑@Overridepublic void setValueAt(Object value, int rowIndex, int columnIndex) {Person person = data.get(rowIndex);switch (columnIndex) {case 0: person.setName((String) value);break;case 1: person.setAge((Integer) value);break;case 2: person.setMarried((Boolean) value);break;}// 通知表格单元格数据已更新fireTableCellUpdated(rowIndex, columnIndex);}// 设置单元格是否可编辑@Overridepublic boolean isCellEditable(int rowIndex, int columnIndex) {return true; // 所有单元格都可编辑}
}    

JTableModel 关键特性

  1. 事件通知机制

    • AbstractTableModel 提供了事件通知方法:
      • fireTableDataChanged():整个表格数据已更改
      • fireTableStructureChanged():表格结构已更改
      • fireTableRowsInserted/Updated/Deleted():行数据更改
      • fireTableCellUpdated():单元格数据更改
  2. 列类型支持

    • 通过getColumnClass()方法返回列的数据类型
    • JTable 会根据列类型自动提供合适的渲染器和编辑器
  3. 单元格编辑

    • 通过isCellEditable()方法控制单元格是否可编辑
    • 通过setValueAt()方法处理编辑后的数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/85332.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/85332.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DDS(Data Distribution Service)

DDS&#xff08;Data Distribution Service&#xff09;是一种以数据为中心的发布/订阅&#xff08;DCPS&#xff09;通信中间件协议栈标准&#xff08;由OMG组织维护&#xff09;。它专为高性能、可预测、实时、可靠的分布式系统设计&#xff0c;广泛应用于国防、航空航天、工…

python爬虫关于多进程,多线程,协程的使用

简介&#xff1a; python其实没有真正意义的多线程&#xff0c;因为有GIL锁存在&#xff0c;但是python3.13去掉GIL锁&#xff0c;有两个版本&#xff0c;python3.13t和python3.13&#xff0c;python3.13去掉GIL锁相当于python底层大规模改变&#xff0c;肯定会影响一些库的使…

java 设计模式_行为型_23状态模式

23.状态模式 Java中的状态设计模式是一种软件设计模式&#xff0c;当对象的内部状态更改时&#xff0c;该模式允许对象更改其行为。状态设计模式通常用于以下情况&#xff1a;对象取决于其状态&#xff0c;并且在运行期间必须根据其内部状态更改其行为。状态设计模式是许多行为…

Flink CDC MySQL 时区相差 8 小时问题优雅解决方式

Flink CDC MySQL 时区相差 8 小时问题解析 代码运行环境 Flink 1.15 + FlinkCDC 2.4.0 + jdk1.8 +springboot 2.31、原因分析 Flink CDC 底层使用 Debezium 连接器来捕获 MySQL 的数据变更,而 Debezium 在解析 MySQL 的 binlog 日志时,默认使用 UTC 时区来处理时间字段。若…

如何在 MX Linux 上安装 Blender CAD 软件

Blender 是一款免费且开源的 CAD 软件,可用于 3D 动画、建模、动态图形、纹理处理、电脑游戏、UV 展开等。同时它也是一款专业的开源程序,是商业软件(如 Maya 或 Cinema 4D)的替代品,支持导入或导出标准格式,如 OBJ、FBX、3DS、PLY 和 STL。Blender 还可以作为视频编辑软…

电脑上的.ssh目录只做什么的

.ssh 目录的作用和来源 系统自动创建 这个目录是在你第一次使用SSH相关功能时自动创建的比如第一次执行 ssh 命令连接服务器时或者使用Git通过SSH协议克隆代码时 主要用途 SSH密钥存储 - 存放公钥/私钥对已知主机记录 - known_hosts 文件记录你连接过的服务器指纹SSH客户端…

Excel大厂自动化报表实战(互联网金融-数据分析周报制作下)

这是Excel大厂自动化报表实战第四期--互联网金融-数据分析周报制作下 数据资源已经与这篇博客捆绑&#xff0c;有需要者可以下载通过网盘分享的文件&#xff1a;2.4自动化报表-8月成交数据.xlsx&#xff0c;2.4自动化报表-8月获客数据.csv等2个文件 链接: https://pan.baidu.c…

界面组件DevExpress WPF中文教程:Grid - 节点(Nodes)概述

DevExpress WPF拥有120个控件和库&#xff0c;将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序&#xff0c;这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 无论是Office办公软件…

开源统一数据库管理平台完全指南:私有化部署方案与技术解析

摘要:面对MySQL、Oracle、Redis等混合数据库环境,如何实现统一管控?本文深度评测5大开源平台,附私有化部署方案和性能对比。 一、核心需求场景与技术选型 典型痛点: #mermaid-svg-LuCYYyJjBakpzzFH {font-family:"trebuchet ms",verdana,arial,sans-serif;font…

hot100 -- 14.贪心算法

1.买卖股票的最佳时机 方法&#xff1a; def MaxProfit(prices):max_pro, min_num 0, float(inf)for num in prices:if num < min_num:min_num nummax_pro max(max_pro, num - min_num)return max_pro 2.跳跃游戏 问题&#xff1a; 给你一个非负整数数组 nums &#…

Celery+fastAPI/Flask实现高性能应用

本文在创作过程中借助 AI 工具辅助资料整理与内容优化。图片来源网络。 引言 大家好&#xff0c;我是沛哥儿。 在当今的软件开发领域&#xff0c;异步任务处理和高效的 Web 开发框架是提升应用性能和可扩展性的关键因素。Celery 作为一个强大的分布式任务队列系统&#xff0c;…

【音视频】PJSIP库——pjsua命令使用详解

1、源码编译 1)安装依赖库 sudo apt install libsrtp2-dev sudo apt install libopus-dev alsa-tools libalsaplayer-dev ffmpeg libalsa* pulseaudio-module-jack sudo apt install jackd libjack-jackd2-dev libjack-dev libsdl2-dev libv4l-dev libavcodec-dev libavde…

Python实例题:图片批量处理工具

目录 Python实例题 题目 问题描述 解题思路 关键代码框架 难点分析 Python实例题 题目 图片批量处理工具 问题描述 开发一个 Python 工具&#xff0c;实现以下功能&#xff1a; 遍历指定文件夹下的所有图片文件&#xff08;支持常见格式如 jpg、png、webp&#xff0…

超图superMap iObjects for Java的Jar使用中遇到的问题

一、 cannot open shared object file: No such file or directory 1. 问题 2. 解决方法 &#xff08;1&#xff09;检查有没有配置环境变量 PATH &#xff08;2&#xff09;创建软连接 ln -s &#xff08;3&#xff09;将主机 /usr/lib64 目录中的libgomp.so.1 复制到 /pla…

常见的蓝牙5.0抗干扰技术和算法

常见的蓝牙5.0抗干扰技术和算法&#xff1a; 跳频扩频&#xff08;Frequency Hopping Spread Spectrum, FHSS&#xff09; 通过在不同的频率通道上快速切换数据传输&#xff0c;减少与固定频率干扰源的冲突。 直接序列扩频&#xff08;Direct Sequence Spread Spectrum, DSSS&…

牛客与Moka深化合作,升级AI面试对接,引领招聘变革

近日&#xff0c;AI 招聘平台牛客与国内领先的人力资源全模块平台 Moka 宣布完成 AI 面试产品的全新对接升级。此次升级实现了从 Moka 到牛客的一键互绑&#xff0c;并打通了简历出题、风险点提问、优势技能挖掘等核心功能&#xff0c;为企业提供更加高效智能的面试体验。 这一…

Vue 3 路由跳转全面指南(Composition API + <script setup>)

一、前言&#xff1a;为什么要学习 Vue Router&#xff1f; 在单页面应用(SPA)开发中&#xff0c;路由管理是核心功能之一。Vue Router 作为 Vue.js 官方推荐的路由解决方案&#xff0c;与 Vue.js 深度集成&#xff0c;提供了以下重要功能&#xff1a; 页面无刷新跳转&#x…

JavaScript基础-常用的键盘事件

一、前言 在网页开发中&#xff0c;用户交互 是非常重要的一环。除了鼠标操作之外&#xff0c;键盘事件也是前端开发中最常见的交互方式之一。 JavaScript 提供了多个用于监听和处理键盘输入的事件&#xff0c;例如 keydown、keyup 和 keypress。掌握这些事件可以帮助我们实现…

解决 Android 项目下载依赖缺失导致的问题

解决 Android 项目下载依赖缺失导致的问题 在项目根目录下的 build.gradle 文件中增加下面的代码&#xff1a; buildscript {repositories {...maven {url "https://maven.aliyun.com/repository/jcenter"}maven {url "https://maven.aliyun.com/repository/c…

Clang Code Model: Error: The clangbackend executable “D:\Soft\Qt5.12.12\Tool

Qt Creator->菜单->帮助->关于插件->C>去掉ClangCodeModel勾选->重启Qt Creator 参考&#xff1a;【问题解决】Qt Creator 报错&#xff1a;Clang Code Model: Error: The clangbackend executable_qt clang code model-CSDN博客