gpt4 book ai didi

java - 在运行时创建 swing 组件

转载 作者:搜寻专家 更新时间:2023-10-31 20:13:36 25 4
gpt4 key购买 nike

我创建了应用程序,它的行为与预期的非常相似。只要数据库查询正在运行,GUI 就会保持响应。使用 SwingUtilities.invokeLater() 创建自定义面板时,GUI 会卡住很短的时间。

当我使用 SwingUtilities.invokeAndWait() 时,它在高端游戏 PC 上运行非常流畅。 (可能不是最好的编码机器......)但在相对较慢的机器(双核,2GB RAM)上,GUI“滞后”

我创建了一个非常小的程序版本来重现该行为。测试时增加 TEST_NUMBER_OF_PANELS 的值。

它将它设置为一个非常大的值,以在我当前的电脑上重现行为,而没有任何花哨的外观和感觉以及额外的组件。但我不想这样发布。所以我把它减少到 100

package test;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.event.TableModelEvent;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

//import org.pushingpixels.substance.api.SubstanceLookAndFeel;
//import org.pushingpixels.substance.api.skin.BusinessBlackSteelSkin;
//import org.pushingpixels.substance.api.skin.SubstanceBusinessBlackSteelLookAndFeel;

public class Test extends JFrame {
private static final int TEST_NUMBER_OF_PANELS = 100;
private static JTabbedPane tabbedPane = new JTabbedPane();
Test() {
this.setLayout(new BorderLayout());
this.setSize(1050, 700);
this.setMinimumSize(new Dimension(400,200));
this.add(tabbedPane, BorderLayout.CENTER);

JButton testbutton = new JButton("new tab");
testbutton.addMouseListener(new MouseListener() {
@Override
public void mousePressed(MouseEvent e) {
tabbedPane.addTab("tab x", new TestTabContent());
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseClicked(MouseEvent e) {
}
});
this.add(testbutton, BorderLayout.NORTH);
//tabbedPane.addTab("tab1", new TestTabContent());
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Test().setVisible(true);
/*
try {
UIManager.setLookAndFeel(new SubstanceBusinessBlackSteelLookAndFeel());
} catch (Exception e) {
System.out.println("Substance Business failed to initialize");
}
SubstanceLookAndFeel.setSkin(new BusinessBlackSteelSkin());
new Test()
.setVisible(true);
*/
}
});

}

private class TestTabContent extends JPanel {
TestTabContent() {
final JPanel boxContainer = new JPanel();
boxContainer.setLayout(new BoxLayout(boxContainer, BoxLayout.Y_AXIS));
JPanel boxContainerOuter = new JPanel();
boxContainerOuter.setLayout(new BorderLayout());
boxContainerOuter.add(boxContainer, BorderLayout.NORTH);
JScrollPane mainScrollPane = new JScrollPane(boxContainerOuter);

// create toolbar
JPanel toolBar = new JPanel();
toolBar.setLayout(new BorderLayout());

//east
JPanel InfoPanel = new JPanel();
InfoPanel.setLayout(new BoxLayout(InfoPanel, BoxLayout.X_AXIS));
InfoPanel.add(new JLabel("test: some info ..."));
toolBar.add(InfoPanel, BorderLayout.WEST);
//west
JPanel viewOptionPanel = new JPanel();
viewOptionPanel.setLayout(new BoxLayout(viewOptionPanel, BoxLayout.X_AXIS));
viewOptionPanel.add(new JLabel("some controls.."));
toolBar.add(viewOptionPanel, BorderLayout.EAST);

// set main panel´s layout
GroupLayout layout = new GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(toolBar, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(mainScrollPane)
);
layout.setVerticalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(toolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0)
.addComponent(mainScrollPane, GroupLayout.DEFAULT_SIZE, 413, Short.MAX_VALUE))
);

// create controls
SwingWorker<String, Void> worker = new SwingWorker<String, Void>() {
@Override
protected String doInBackground() throws Exception {
// RUN DATABASE QUERY
// ------------------
//Thread.sleep(1000);
// ------------------
// CREATE TESTPANELS

ArrayList<ArrayList<ArrayList<String>>> dataFromQuery = createDummyData();

for (final ArrayList<ArrayList<String>> tableData : dataFromQuery) {
//SwingUtilities.invokeAndWait(new Runnable() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// create panels on edt
TestPanel newTestPanel = new TestPanel(tableData);
JPanel seperator = new JPanel(new BorderLayout());
seperator.setBackground(Color.black);
seperator.add(newTestPanel);

boxContainer.add(seperator);
}
});
}
return "";
}

};
worker.execute();
}
private ArrayList<ArrayList<ArrayList<String>>> createDummyData () {
ArrayList<String> columns = new ArrayList<String>();
ArrayList<ArrayList<String>> rows = new ArrayList<ArrayList<String>>();
ArrayList<ArrayList<ArrayList<String>>> tables = new ArrayList<ArrayList<ArrayList<String>>>();
for (int i = 0; i < 15; i ++) {
columns.add("test213124");
}
for (int i=0; i < 8; i++) {
rows.add(columns);
}
for (int i=0; i < TEST_NUMBER_OF_PANELS; i++) {
tables.add(rows);
}
return tables;
}
}
public class TestPanel extends JPanel {
private static final long serialVersionUID = -3853151036184428736L;
public static final int radioButtonWidth = 20;


private JTable table;
private DefaultTableModel tableModel;
private JPanel collapsiblePane;
private JButton collapsingButton;

TestPanel(ArrayList<ArrayList<String>> tableData) {
System.out.println("testpanel constructor");
createTestPanel(tableData);
}

private void createTestPanel(ArrayList<ArrayList<String>> tableData) {
// container with boxLayout for collapsiblePane
JPanel boxContainer = new JPanel();
boxContainer.setLayout(new BoxLayout(boxContainer, BoxLayout.Y_AXIS));
boxContainer.setBorder(BorderFactory.createMatteBorder(0, 1, 1, 1, Color.BLACK));

// set table stuff
tableModel = new DefaultTableModel();

tableModel.setColumnIdentifiers(
new Object[] {
"test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test"});


for (ArrayList<String> rowData : tableData) {
Vector<Serializable> data = new Vector<Serializable>();

for (String columnData : rowData) {
data.add(columnData);
}
tableModel.addRow(data);

}
table = new JTable(tableModel) {
public void tableChanged(TableModelEvent e) {
super.tableChanged(e);
repaint();
}

public Component prepareRenderer(TableCellRenderer renderer, int row, int column){
Component returnComp = super.prepareRenderer(renderer, row, column);
Color alternateColor = new Color(225,225,238);
Color usualColor = Color.WHITE;
if (!returnComp.getBackground().equals(getSelectionBackground())){
Color bg = (row % 2 == 0 ? alternateColor : usualColor);
returnComp .setBackground(bg);
bg = null;
}
return returnComp;
}
};

boxContainer.add(table.getTableHeader(), BorderLayout.NORTH);
boxContainer.add(table, BorderLayout.CENTER);

// other controls / toolbar
JPanel toolbar = new JPanel();
toolbar.setLayout(new BorderLayout());

// buttons to the right
JPanel toolbarButtonGroup = new JPanel();
toolbarButtonGroup.setLayout(new BoxLayout(toolbarButtonGroup, BoxLayout.X_AXIS));

// test button
JButton button = new JButton("test");
JPanel sepPanel = new JPanel();
sepPanel.add(button);
toolbarButtonGroup.add(sepPanel);
// test button
button = new JButton("test");
sepPanel = new JPanel();
sepPanel.add(button);
toolbarButtonGroup.add(sepPanel);
// test button
button = new JButton("test");
sepPanel = new JPanel();
sepPanel.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
sepPanel.add(button);

toolbarButtonGroup.add(sepPanel);

toolbar.add(toolbarButtonGroup, BorderLayout.EAST);
boxContainer.add(toolbar);

JPanel subPanel = new JPanel();
subPanel.setLayout(new BoxLayout(subPanel, BoxLayout.Y_AXIS));

JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new BorderLayout());
buttonPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 24));

collapsingButton = new JButton(tableModel.getValueAt(0, 8).toString());
collapsingButton.setName("toggleButton");
collapsingButton.setHorizontalAlignment(SwingConstants.LEFT);
collapsingButton.setBorderPainted(false);
collapsingButton.setFocusPainted(false);

buttonPanel.add(collapsingButton, BorderLayout.CENTER);
buttonPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
subPanel.add(buttonPanel);

collapsiblePane = new JPanel();

collapsiblePane.setName("collapsiblePane");
collapsiblePane.setLayout(new CardLayout());

collapsiblePane.add(boxContainer, "");
subPanel.add(collapsiblePane);

add(subPanel);
}
}
}

我想我应该使用 SwingWorker 而不是在 EDT 上运行尽可能多的代码。我知道我应该在单独的线程中访问 TableModel。如果应用程序中只有一个 JTable,那很简单:我在 EDT 上创建表并在线程上更新数据。

在那种情况下,我不确定哪种方法是可取的。现在,所有与 tabe 相关的内容都在 TestPanel 类中进行管理。完全在 EDT 上运行。

当然,我可以在 TestPanel 中运行一个线程来处理 TableModel,但是为每个面板创建一个新线程对我来说听起来不是个好主意。

另一个“想法”是在 TestTab 中直接在运行数据库查询的同一线程上创建模型。但由于它属于 TestPanel,因此这种方法听起来像是糟糕的设计。

到目前为止,我有过的最肮脏的想法是使用 invokeAndWait() 并让 Tread.sleep() 运行一段时间,这样 ETD 就不会每隔几毫秒就被新的调用打断。但我实际上不想那样编码。

哪种设计方法最可取?


我想在运行时在 JTabbedPane 中创建几个自定义面板。自定义面板的数量取决于数据库查询的结果集。

每个自定义面板都包含一个 JTable,其中包含来自结果集的一大块数据和一些 JButton。

我的计划是使用 SwingWorker 在单独的线程上运行数据库查询。然后使用 invokeLater() 在事件调度线程上安排任务以创建自定义面板,因为必须在 EDT 中创建和访问 swing 组件。

使用这种方法,如果结果集包含很多行,则在创建自定义面板时 gui 可能会卡住。

解决或最小化此问题的最优雅方法是什么?


最佳答案

您可能应该首先考虑限制显示的结果数量!

除此之外,Swing 组件的创建非常高效。事实上,我希望它能够像从数据库返回结果一样快地创建屏幕外组件实例,如果不是更快的话。您确定这真的是瓶颈吗?

最后,如果您担心卡住,您始终可以使用 invokeLater 为每个自定义面板触发单独的事件。然后将有机会在每个面板创建之间发生事件处理,这应该会消除“卡住”效果。

关于java - 在运行时创建 swing 组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14195060/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com