收藏 分享(赏)

JAVA教程 第七讲 Swing用户界面设计.doc

上传人:dzzj200808 文档编号:2249987 上传时间:2018-09-07 格式:DOC 页数:21 大小:68.50KB
下载 相关 举报
JAVA教程 第七讲 Swing用户界面设计.doc_第1页
第1页 / 共21页
JAVA教程 第七讲 Swing用户界面设计.doc_第2页
第2页 / 共21页
JAVA教程 第七讲 Swing用户界面设计.doc_第3页
第3页 / 共21页
JAVA教程 第七讲 Swing用户界面设计.doc_第4页
第4页 / 共21页
JAVA教程 第七讲 Swing用户界面设计.doc_第5页
第5页 / 共21页
点击查看更多>>
资源描述

1、JAVA 教程 第七讲 Swing 用户界面设计 2012-1-9 20:22| 发布者: admin| 查看: 4229| 评论: 0摘要: 71 Swing 简介 7.1.1 简介 第五讲中我们学习了 AWT,AWT 是Swing 的基础。Swing 的产生主要原因就是 AWT 不能满足图形化用户界面发展的需要。AWT 设计的初衷是支持开发小应用程序的简单用户界面。例如 AWT 缺少剪贴板、打印 .71 Swing 简介7.1.1 简介第五讲中我们学习了 AWT,AWT 是 Swing 的基础。Swing 的产生主要原因就是 AWT 不能满足图形化用户界面发展的需要。AWT 设计的初衷是支

2、持开发小应用程序的简单用户界面。例如 AWT 缺少剪贴板、打印支持、键盘导航等特性,而且原来的 AWT 甚至不包括弹出式菜单或滚动窗格等基本元素。此外 AWT 还存在着严重的缺陷,人们使 AWT 适应基于继承的、具有很大伸缩性的事件模型,基于同位体的体系结构也成为其致命的弱点。随着发展的需要,Swing 出现了,Swing 组件几乎都是轻量组件,与重量组件相比,没有本地的对等组件,不像重量组件要在它们自己的本地不透明窗体中绘制,轻量组件在它们的重量组件的窗口中绘制。这一讲我们讲一下基本的 Swing 组件使用方法和使用 Swing 组件创建用户界面的初步方法。Swing 是由 100%纯 Ja

3、va 实现的,Swing 组件是用 Java 实现的轻量级( light-weight)组件,没有本地代码,不依赖操作系统的支持,这是它与 AWT组件的最大区别。由于 AWT 组件通过与具体平台相关的对等类(Peer)实现,因此 Swing 比 AWT 组件具有更强的实用性。Swing 在不同的平台上表现一致,并且有能力提供本地窗口系统不支持的其它特性。Swing 采用了一种 MVC 的设计范式,即“模型-视图-控制“(Model-View-Controller),其中模型用来保存内容,视图用来显示内容,控制器用来控制用户输入。Swing 外观感觉采用可插入的外观感觉(Pluggable Lo

4、ok and Feel,PL /引入 Swing 包名/import com.sun.java.swing.*;/使用 JDK 1.2 Beta 4 版和所有 Swing 1.1 Beta 3/之前的版本,引入 Swing 包名用此方法。import java.awt.*;import java.awt.event.*;public class SwingApplication private static String labelPrefix = “Number of button clicks: “;private int numClicks = 0; /计数器,计算点击次数public

5、Component createComponents() final JLabel label = new JLabel(labelPrefix + “0 “);JButton button = new JButton(“Im a Swing button!“);button.setMnemonic(KeyEvent.VK_I); /设置按钮的热键为Ibutton.addActionListener(new ActionListener() public void actionPerformed(ActionEvent e) numClicks+;label.setText(labelPref

6、ix + numClicks);/显示按钮被点击的次数);label.setLabelFor(button);/* 在顶层容器及其内容之间放置空间的常用办法是把内容添加到Jpanel 上,而 Jpanel 本身没有边框的。*/JPanel pane = new JPanel();pane.setBorder(BorderFactory.createEmptyBorder(30, /top30, /left10, /bottom30) /right);pane.setLayout(new GridLayout(0, 1); /单列多行pane.add(button);pane.add(label

7、);return pane;public static void main(String args) try UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName();/设置窗口风格 catch (Exception e) /创建顶层容器并添加内容.JFrame frame = new JFrame(“SwingApplication“);SwingApplication app = new SwingApplication();Component contents = app.createCompone

8、nts();frame.getContentPane().add(contents, BorderLayout.CENTER);/窗口设置结束,开始显示frame.addWindowListener(new WindowAdapter() /匿名类用于注册JianTingQipublic void windowClosing(WindowEvent e) System.exit(0););frame.pack();frame.setVisible(true);查看运行结果7.1.9 Swing 程序结构简介Swing 的程序设计一般可按照下列流程进行:1 引入 Swing 包2 选择“外观和感

9、觉“3 设置顶层容器4 设置按钮和标签5 向容器中添加组件6 在组件周围添加边界7 进行事件处理例子 7.1 说明了 Swing 中程序设计的结构以及最基本的组件 Button 和Label 的用法。在程序中,我们建立一个 Swing 风格的窗口,并在其中添加一个按钮,程序中保存一个计数器以计算按钮被点击的次数,并在每一次点击之后用一个 Label 显示。在这个程序中我们可以看到 Swing 组件的使用与 AWT 组件的使用基本方法一致,使用的事件处理机制也完全相同。这些在前面的 AWT中已经讲过,不再赘述。#NextPage#72 Swing 组件和容器在 Swing 中不但用轻量级的组件替

10、代了 AWT 中的重量级的组件,而且Swing 的替代组件中都包含有一些其他的特性。例如,Swing 的按钮和标签可显示图标和文本,而 AWT 的按钮和标签只能显示文本。Swing 中的大多数组件都是 AWT 组件名前面加了一个“J“。7.2.1 组件的分类Jcomponent 是一个抽象类,用于定义所有子类组件的一般方法,其类层次结构如下所示:java.lang.Object|+-java.awt.Component|+-java.awt.Container|+-javax.swing.JComponent并不是所有的 Swing 组件都继承于 JComponent 类,JComponent

11、 类继承于Container 类,所以凡是此类的组件都可作为容器使用。组件从功能上分可分为:1) 顶层容器:JFrame,JApplet,JDialog,JWindow 共 4 个2) 中间容器:JPanel,JScrollPane,JSplitPane,JToolBar 3) 特殊容器:在 GUI 上起特殊作用的中间层,如JInternalFrame,JLayeredPane,JRootPane.4) 基本控件:实现人际交互的组件,如 Jbutton, JComboBox, JList, JMenu, JSlider, JtextField。5) 不可编辑信息的显示:向用户显示不可编辑信息的

12、组件,例如 JLabel, JProgressBar, ToolTip。6) 可编辑信息的显示:向用户显示能被编辑的格式化信息的组件,如JColorChooser, JFileChoose, JFileChooser, Jtable, JtextArea。JComponent 类的特殊功能又分为:1) 边框设置:使用 setBorder()方法可以设置组件外围的边框,使用一个EmptyBorder 对象能在组件周围留出空白。2) 双缓冲区:使用双缓冲技术能改进频繁变化的组件的显示效果。与 AWT组件不同,JComponent 组件默认双缓冲区,不必自己重写代码。如果想关闭双缓冲区,可以在组件上

13、施加 setDoubleBuffered(false)方法。3) 提示信息:使用 setTooltipText()方法,为组件设置对用户有帮助的提示信息。4) 键盘导航:使用 registerKeyboardAction( ) 方法,能使用户用键盘代替鼠标来驱动组件。JComponent 类的子类 AbstractButton 还提供了便利的方法用 setMnemonic( )方法指明一个字符,通过这个字符和一个当前 L/把其它组件添加到 Jpanel 中;frame.setContentPane(contentPane);/把 contentPane 对象设置成为 frame 的内容面板7.

14、2.3 各种容器面板和组件看图根面板由一个玻璃面板(glassPane)、一个内容面板(contentPane)和一个可选择的菜单条(JMenuBar)组成,而内容面板和可选择的菜单条放在同一分层。玻璃面板是完全透明的,缺省值为不可见,为接收鼠标事件和在所有组件上绘图提供方便。根面板提供的方法:Container getContentPane(); /获得内容面板setContentPane(Container); /设置内容面JMenuBar getMenuBar( ); /活动菜单条setMenuBar(JMenuBar); /设置菜单条JLayeredPane getLayeredPan

15、e(); /获得分层面板setLayeredPane(JLayeredPane); /设置分层面板Component getGlassPane(); /获得玻璃面板setGlassPane(Component); /设置玻璃面板7.2.3.2 分层面板(JLayeredPane)Swing 提供两种分层面板:JlayeredPane 和 JDesktopPane。 JDesktopPane 是 JLayeredPane 的子类,专门为容纳内部框架(JInternalFrame)而设置。向一个分层面板种添加组件,需要说明将其加入哪一层,指明组件在该层中的位置:add(Component c, I

16、nteger Layer, int position)。7.2.3.3 面板(JPanel)面板(JPanel)是一个轻量容器组件,用法与 Panel 相同,用于容纳界面元素,以便在布局管理器的设置下可容纳更多的组件,实现容器的嵌套。Jpanel, JscrollPane, JsplitPane, JinteralFrame 都属于常用的中间容器,是轻量组件。Jpanel 的缺省布局管理器是 FlowLayout。java.lang.Object|+-java.awt.Component|+-java.awt.Container|+-javax.swing.JComponent|+-javax

17、.swing.JPanel7.2.3.4 滚动窗口(JScrollPane)看图 1 看图 2JscrollPane 是带滚动条的面板,主要是通过移动 JViewport(视口)来实现的。JViewport 是一种特殊的对象,用于查看基层组件,滚动条实际就是沿着组件移动视口,同时描绘出它在下面“看到“的内容。7.2.3.5 分隔板(JSplitPane)java.lang.Object|+-java.awt.Component|+-java.awt.Container|+-javax.swing.JComponent|+-javax.swing.JSplitPane看图JSplitPane 提

18、供可拆分窗口,支持水平拆分和垂直拆分并带有滑动条。常用方法有:addImpl(Component comp,Object constraints,int index)/增加指定的组件setTopComponent(Component comp) /设置顶部的组件setDividerSize(int newSize) /设置拆分的大小setUI(SplitPaneUI ui) /设置外观和感觉7.2.3.6 选项板(JTabbedPane)看图JTabbedPane 提供一组可供用户选择的带有标签或图标的开关键。常用方法:add(String title,Component component)

19、 /增加一个带特定标签的组件addChangeListener(ChangeListener l) /选项板注册一个变化JianTingQi7.2.3.7 工具栏(JToolBar)工具栏在左上角工具栏在右侧JtoolBar 是用于显示常用工具控件的容器。用户可以拖拽出一个独立的可显示工具控件的窗口。常用方法有:JToolBar(String name) /构造方法getComponentIndex(Component c) /返回一个组件的序号getComponentAtIndex(int i) /得到一个指定序号的组件7.2.3.8 内部框架(JInternalFrame)看图内部框架 J

20、InternalFrame 就如同一个窗口在另一个窗口内部,其特点如下:1) 必须把内部框架添加到一个容器中(通常为 JDesktopPane),否则不显示;2) 不必调用 show()或 setVisible()方法,内部框架随所在的容器一起显示;3) 必须用 setSize()或 pack()或 setBounds 方法设置框架尺寸,否则尺寸为零,框架不能显示;4) 可以用 setLocation()或 setBounds( ) 方法设置内部框架在容器中的位置,缺省值为 0,0,即容器的左上角;5) 象顶层 JFrame 一样,对内部框架添加组件也要加在它的内容面板上;6) 在内部框架中建

21、立对话框,不能使用 JDialog 作为顶层窗口,必须用JOptionPane 或 JInternalFrame;7) 内部框架不能监听窗口事件,可以通过监听与窗口事件类似的内部框架(JInternalFrameEvent)处理内部框架窗口的操作。JFrame frame=new JFrame(“InternalFrameDemo“); /实例化窗口JDesktopPane desktop=new JDesktopPane(); /实例化容器JDesktopPaneMyInternalFrame myframe=new MyInternalFrame(); /实例化内部窗口desktop.ad

22、d(myframe); /把内部窗口添加到容器中myframe.setSelected(true); /内部面板是可选择的frame.setContentPane(desktop); /把 desktop 设为 frame 的内容面板7.2.3.9 按钮(JButton)按钮是一个常用组件,按钮可以带标签或图象。 java.lang.Object|+-java.awt.Component|+-java.awt.Container|+-javax.swing.JComponent|+-javax.swing.AbstractButton|+-javax.swing.JButton常用的构造方法有

23、:JButton(Icon icon) /按钮上显示图标JButton(String text) /按钮上显示字符JButton(String text, Icon icon) /按钮上既显示图标又显示字符例 72public class ButtonDemo extends Jpanel implements ActionListenerJButton b1,b2,b3;public ButtonDemo() super();ImageIcon leftButtonIcon=new ImageIcon(“images/right.gif);/显示在左按钮上的图标ImageIcon middl

24、eButtonIcon=new ImageIcon(“images/middle.gif);/显示在中间按钮上的图标ImageIcon middleButtonIcon=new ImageIcon(“images/left.gif);/显示在右按钮上的图标b1=new JButton(“Disable middle button“,leftButtonIcon);/按钮 b1 上同时显示文字和图标b1.setVerticalTextPosition(AbstractButton.CENTER);/按钮 b1 上的文字在垂直方向上是居中对齐b1.setHorizontalTextPosition

25、(AbstractButton.LEFT);/按钮 b1 上的文字在水平居方向上是居左对齐b1.setMnemonic(d); /设置按钮 b1 的替代的键盘按键是db1.setActionCommand(“diaable“);看图7.2.3.10 复选框(JCheckBox)复选框提供简单的“on/off“开关,旁边显示文本标签。如图7.2.3.11 单选框(JRadioButton)单选框 JRadioButton 与 AWT 中的复选框组功能类似。如图7.2.3.12 选择框(JComboBox)JComboBox 每次只能选择其中的一项,但是可编辑每项的内容,而且每项的内容可以是任意类

26、,而不再局限于 String。如图7.2.3.13 文件选择器(JFileChooser)JFileChooser 内建有“打开“,“存储“两种对话框,还可以自己定义其他种类的对话框。如图7.2.3.14 标签(JLabel)提供可带图形的标签 如图7.2.3.15 列表(List)适用于数量较多的选项以列表形式显示,里面的项目可以由任意类型对象构成。支持单选和多选。如图7.2.3.16 菜单(JMenu)JMenu 与 AWT 的菜单 Menu 的不同之处是它可以通过 setJMenuBar(menubar)将菜单放置到容器中的任意地方。如图7.2.3.17 进程条(JProgressBar

27、)进程条是提供一个直观的图形化的进度描述,从“空“到“满“的过程。如图7.2.3.18 滑动条(JSlider)滑动条使得用户能够通过一个滑块的来回移动来输入数据。如图#NextPage#7.2.3.19 表格(JTable)表格是 Swing 新增加的组件,主要功能是把数据以二维表格的形式显示出来。使用表格,依据 M-V-C 的思想,最好先生成一个 MyTableModel 类型的对象来表示数据,这个类是从 AbstractTableModel 类中继承来的,其中有几个方法是一定要重写,例如getColumnCount,getRowCount,getColumnName,getValueAt

28、。因为 Jtable 会从这个对象中自动获取表格显示所必需的数据,AbstractTableModel 类的对象负责表格大小的确定(行、列)、内容的填写、赋值、表格单元更新的检测等等一切跟表格内容有关的属性及其操作。JTable 类生成的对象以该 TableModel为参数,并负责将 TableModel 对象中的数据以表格的形式显示出来。JTable 类常用的方法有:getModel() /获得表格的数据来源对象JTable(TableModel dm) /dm 对象中包含了表格要显示的数据/下列两个构造方法,第一个参数是数据,第二个参数是表格第一行中显示的内容JTable(objectro

29、wData,objectcolumnNams);JTable(VectorrowData,VectorcolumnNams);例 7.3 RecorderOfWorkersimport javax.swing.JTable;import javax.swing.table.AbstractTableModel;import javax.swing.JScrollPane;import javax.swing.JFrame;import javax.swing.SwingUtilities;import javax.swing.JOptionPane;import java.awt.*;impo

30、rt java.awt.event.*;public class TableDemo extends JFrame private boolean DEBUG = true;public TableDemo() /实现构造方法super(“RecorderOfWorkers“); /首先调用父类 JFrame 的构造方法生成一个窗口MyTableModel myModel = new MyTableModel();/myModel 存放表格的数据JTable table = new JTable(myModel);/表格对象 table 的数据来源是 myModel 对象table.setPr

31、eferredScrollableViewportSize(new Dimension(500, 70);/表格的显示尺寸/产生一个带滚动条的面板JScrollPane scrollPane = new JScrollPane(table);/将带滚动条的面板添加入窗口中getContentPane().add(scrollPane, BorderLayout.CENTER);addWindowListener(new WindowAdapter() /注册窗口JianTingQipublic void windowClosing(WindowEvent e) System.exit(0);)

32、;/把要显示在表格中的数据存入字符串数组和 Object 数组中class MyTableModel extends AbstractTableModel /表格中第一行所要显示的内容存放在字符串数组 columnNames 中final String columnNames = “First Name“,“Position“,“Telephone“,“MonthlyPay“,“Married“;/表格中各行的内容保存在二维数组 data 中final Object data = “Wangdong“, “Executive“,“01068790231“, new Integer(5000),

33、 new Boolean(false),“LiHong“, “Secretary“,“01069785321“, new Integer(3500), new Boolean(true),“LiRui“, “Manager“,“01065498732“, new Integer(4500), new Boolean(false),“ZhaoXin“, “Safeguard“,“01062796879“, new Integer(2000), new Boolean(true),“ChenLei“, “Salesman“,“01063541298“, new Integer(4000), new

34、 Boolean(false);/下述方法是重写 AbstractTableModel 中的方法,其主要用途是被 JTable 对象调用,以便在表格中正确的显示出来。程序员必须根据采用的数据类型加以恰当实现。/获得列的数目public int getColumnCount() return columnNames.length;/获得行的数目public int getRowCount() return data.length;/获得某列的名字,而目前各列的名字保存在字符串数组columnNames 中public String getColumnName(int col) return co

35、lumnNamescol;/获得某行某列的数据,而数据保存在对象数组 data 中public Object getValueAt(int row, int col) return datarowcol;/判断每个单元格的类型public Class getColumnClass(int c) return getValueAt(0, c).getClass();/将表格声明为可编辑的public boolean isCellEditable(int row, int col) if (col 2) return false; else return true;/改变某个数据的值public

36、void setValueAt(Object value, int row, int col) if (DEBUG) System.out.println(“Setting value at “ + row + “,“ + col+ “ to “ + value+ “ (an instance of “+ value.getClass() + “)“);if (data0col instanceof IntegerfireTableCellUpdated(row, col); catch (NumberFormatException e) JOptionPane.showMessageDial

37、og(TableDemo.this,“The “ + getColumnName(col)+ “ column accepts only integer values.“); else datarowcol = value;fireTableCellUpdated(row, col);if (DEBUG) System.out.println(“New value of data:“);printDebugData();private void printDebugData() int numRows = getRowCount();int numCols = getColumnCount()

38、;for (int i=0; i numRows; i+) System.out.print(“ row “ + i + “:“);for (int j=0; j numCols; j+) System.out.print(“ “ + dataj);System.out.println();System.out.println(“-“);public static void main(String args) TableDemo frame = new TableDemo();frame.pack();frame.setVisible(true);7.2.3.20 树(JTree)要显示一个层

39、次关系分明的一组数据,用树状图表示能给用户一个直观而易用的感觉,JTree 类如同 Windows 的资源管理器的左半部,通过点击可以“打开“、“关闭“文件夹,展开树状结构的图表数据。JTree 也是依据 M-V-C 的思想来设计的,Jtree 的主要功能是把数据按照树状进行显示,其数据来源于其它对象,其显示效果通常如下图所示下面是一棵包含六个分枝点的树的例子,来演示 JTree 的实现过程。import java.awt.*;import java.awt.event.*;import javax.swing.*;import javax.swing.tree.*;class BranchD

40、efaultMutableTreeNode r;/DefaultMutableTreeNode 是树的数据结构中的通用节点,节点也可以有多个子节点。public Branch(String data)r=new DefaultMutableTreeNode(data0);for(int i=1;i r.add(new DefaultMutableTreeNode(data);/给节点 r 添加多个子节点public DefaultMutableTreeNode node()/返回节点return r;public class Trees extends JPanelString data=“C

41、olors“,“Red“,“Blue“,“Green“,“Flavors“,“Tart“,“Sweet“,“Bland“,“Length“,“Short“,“Medium“,“Long“,“Volume“,“High“,“Medium“,“Low“,“Temperature“,“High“,“Medium“,“Low“,“Intensity“,“High“,“Medium“,“Low“;static int i=0; /I 用于统计按钮点击的次数DefaultMutableTreeNode root,child,chosen;JTree tree;DefaultTreeModel model;

42、public Trees()setLayout(new BorderLayout();root=new DefaultMutableTreeNode(“root“);/根节点进行初始化tree=new JTree(root);/树进行初始化,其数据来源是 root 对象add(new JScrollPane(tree);/把滚动面板添加到 Trees 中model=(DefaultTreeModel)tree.getModel();/获得数据对象 DefaultTreeModelJButton test=new JButton(“Press me“);/按钮 test 进行初始化test.ad

43、dActionListener(new ActionListener()/按钮 test 注册 JianTingQipublic void actionPerformed(ActionEvent e)if (i /按钮 test 点击的次数小于 data 的长度child=new Branch(datai+).node();/生成子节点chosen=(DefaultMutableTreeNode)/选择 child 的父节点tree.getLastSelectedPathComponent();if(chosen=null) chosen=root;model.insertNodeInto(c

44、hild,chosen,0);/把 child 添加到 chosen);test.setBackground(Color.blue);/按钮 test 设置背景色为蓝色test.setForeground(Color.white);/按钮 test 设置前景色为白色JPanel p=new JPanel();/面板 p 初始化p.add(test);/把按钮添加到面板 p 中add(p,BorderLayout.SOUTH);/把面板 p 添加到 Trees 中public static void main(String args)JFrame jf=new JFrame(“JTree dem

45、o“);jf.getContentPane().add(new Trees(), BorderLayout.CENTER);/把 Trees 对象添加到 JFrame 对象的中央jf.setSize(200,500);jf.setVisible(true);运行结果是多种多样的,与用户点击按钮的次序有关,其中一种结果如下7.2.4 布局管理器和 AWT 相同,为了容器中的组件能实现平台无关的自动合理排列,Swing也采用了布局管理器来管理组件的排放、位置、大小等布置任务,在此基础上将显示风格做了改进。另外一个不同点在于 Swing 虽然有顶层容器,但是我们不能把组件直接加到顶层容器中,Swin

46、g 窗体中含有一个称为内容面板的容器(ContentPane),在顶层容器上放内容面板,然后把组件加入到内容面板中,前面已讲过如何得到和设置内容面板。所以,在 Swing 中,设置布局管理器是针对于内容面板的,另外 Swing 新增加了一个 BoxLayout 布局管理器。显示上与 AWT 略有不同,如下图所示:现在简单介绍一下 BoxLayout 布局管理器BoxLayout 布局管理器按照自上而下(y 轴)或者从左到右(x 轴)的顺序布局依次加入组件。建立一个 BoxLayout 对象,必须指明两个参数:被布局的容器和 BoxLayout 的主轴。缺省情况下,组件在纵轴方向上居中对齐。设置

47、布局管理器的方法如下:pane.setLayout(new BoxLayout(pane,BoxLayout.Y-AXIS);JScrollPane listScroller=new JScrollPane(list);listScroller.setPreferredSize(new Demension(250,80);listScroller.setMinimumSize(new Dimension(250,80);listScroller.setAlignmentX(LEFT_ALIGNMENT);/从上到下设置标签和滚动板.JPanel listPane=new JPanel();li

48、stPane.setLayout(new BoxLayout(listPanae,BoxLayout,Y_AXIS);JLabel label=new JLabel(labelText);listPane.add(label);listPane.add(Box.createRigidArea(new Demension(0,5);listPane.add(listScroller);listPane.setBorder(BorderFactory.creatEmptyBorder(10,10,10,10);/从左到右设置按钮JPanel buttonPane=new JPanel();buttonPane.setLayout(new BoxLayout(buttonPane,Boxlayout.X_AXIS);buttonPane.setBoder(BorderFactory.createEmptyBorder(0,10,10,10);buttonPane.add(Box.createHorizontalGlue();buttonPane.add(cancelButton);buttonPa

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 大学课件

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报