gpt4 book ai didi

java - JComboBox 下拉列表中的 JPanel 但不在编辑器中

转载 作者:搜寻专家 更新时间:2023-11-01 03:49:57 25 4
gpt4 key购买 nike

我想要的东西看起来比较简单,我也差不多了。这最终将用于扩展 TableCellEditor,因此大小很重要。我想要的是这样的: Mock-up of ideal JPanelComboBox

结合使用自定义 ComboBoxEditorListCellRenderer 我已经能够得到这样的东西:

Mock-up of best attempt at JPanelComboBox

有以下不便之处:

  • 切断超出 JComboBox 原始宽度的任何组件
  • 强制 JComboBox 的高度为下拉列表中 JPanel 的高度
  • 在下拉列表消失之前只允许单击一 (1) 次表单修改。

我想让下拉列表保持可见,直到用户单击编辑器或 JComboBox 将焦点移到另一个控件,然后更新编辑器中的值。下拉列表中永远只有一 (1) 个 JPanel,我不希望编辑器能够实际编辑显示的字符串。

我的问题类似于@ErkanHaspalut 的 question here但两种 react 都不令人满意。我之前通过在 JPopupMenu 中嵌入 JPanel 并将其添加到 JTextField 中进行了类似的尝试,但是对于弹出窗口消失有类似的问题过早地。

我尝试通过设置 setMaximumSize height 值(无效)和

    Rectangle tmp = cboTest.getBounds();
tmp.height = 24;
cboTest.setBounds(tmp);

它仅显示 JComboBox 的前 24 行。一个最小的可编译示例是

/*
* Program to test having a JPanel in the JComboBox's drop-down but not the JComboBox's editor.
*/
package testdropdownsubform;

import java.awt.Component;
import java.awt.Rectangle;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javafx.application.Application;
import javafx.stage.Stage;
import javax.swing.ComboBoxEditor;
import javax.swing.JComboBox;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.JTextField;
import javax.swing.plaf.basic.BasicComboBoxEditor;

/**
* @author Masked Coder
*/

public class Dim {
public Long DimWidth;
public Long DimHeight;

public Dim () {
DimWidth = 1L;
DimHeight = 1L;
}

@Override
public String toString() {
return DimWidth.toString() + "\' x " + DimHeight.toString() + "\'";
}
}

public class DimPanel extends javax.swing.JPanel {

public DimPanel() {
spnDimWidth = new javax.swing.JSpinner();
spnDimHeight = new javax.swing.JSpinner();

spnDimWidth.setModel(new javax.swing.SpinnerNumberModel(Long.valueOf(1L), Long.valueOf(0L), null, Long.valueOf(1L)));
spnDimWidth.setPreferredSize(new java.awt.Dimension(50, 24));
addComponent(spnDimWidth);

lblTween.setText(" x ");
addComponent(lblTween);

spnDimHeight.setModel(new javax.swing.SpinnerNumberModel(Long.valueOf(1L), Long.valueOf(0L), null, Long.valueOf(1L)));
spnDimHeight.setPreferredSize(new java.awt.Dimension(50, 24));
addComponent(spnDimHeight);
}

private javax.swing.JSpinner spnDimWidth;
private javax.swing.JLabel lblTween;
private javax.swing.JSpinner spnDimHeight;
}


public class DimListCellRenderer implements ListCellRenderer {
private DimPanel dpDim;

public DimListCellRenderer(DimPanel newDimPanel) {
dpDim = newDimPanel;

}

@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Dim dValue = (Dim) value;
dpDim.setDim(dValue);
return dpDim;
}

}

public class DimComboBoxEditor extends BasicComboBoxEditor implements ComboBoxEditor {
JTextField txtDim = new JTextField();
Dim Item = new Dim();

public DimComboBoxEditor() {
txtDim.setEnabled(false);
txtDim.setOpaque(true);
}
@Override
public Component getEditorComponent() {
txtDim.setText(Item.toString());
return txtDim;
}

@Override
public void setItem(Object anObject) {
Item = (Dim) anObject;
}

@Override
public Object getItem() {
return Item;
}

@Override
public void selectAll() {
txtDim.selectAll();
}

@Override
public void addActionListener(ActionListener l) {
txtDim.addActionListener(l);
}

@Override
public void removeActionListener(ActionListener l) {
txtDim.removeActionListener(l);
}

}

public class MainTestForm extends javax.swing.JFrame {
public MainTestForm() {
lblPrevComponent = new javax.swing.JLabel();
chkPrevComponent = new javax.swing.JCheckBox();
lblTest = new javax.swing.JLabel();
cboTest = new JComboBox<testdropdownsubform.DicePanel>();
lblNextComponent = new javax.swing.JLabel();
scpNextComponent = new javax.swing.JScrollPane();
txaNextComponent = new javax.swing.JTextArea();
btnForceHeight = new javax.swing.JButton();

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

lblPrevComponent.setText("Prev. Component");

chkPrevComponent.setText("jCheckBox1");

lblTest.setText("Dimension");

cboTest.setEditable(true);
cboTest.setEditor(new DimComboBoxEditor());
cboTest.setRenderer(new DimListCellRenderer(new DimPanel()));
cboTest.addItem(new Dim());

lblNextComponent.setText("Next Component");

txaNextComponent.setColumns(20);
txaNextComponent.setRows(5);
scpNextComponent.setViewportView(txaNextComponent);

btnForceHeight.setText("Force");
btnForceHeight.setToolTipText("Force test combobox height");
btnForceHeight.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnForceHeightActionPerformed(evt);
}
});

.addComponent(lblPrevComponent)
.addComponent(chkPrevComponent))
.addComponent(lblTest)
.addComponent(cboTest)
.addComponent(lblNextComponent)
.addComponent(scpNextComponent)
.addComponent(btnForceHeight))

}

private void btnForceHeightActionPerformed(java.awt.event.ActionEvent evt) {
Rectangle tmp = cboTest.getBounds();
tmp.height = 24;
cboTest.setBounds(tmp);
}

/**
* @param args the command line arguments
*/
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new MainTestForm().setVisible(true);
}
});
}

private javax.swing.JButton btnForceHeight;
private javax.swing.JComboBox cboTest;
private javax.swing.JCheckBox chkPrevComponent;
private javax.swing.JLabel lblNextComponent;
private javax.swing.JLabel lblPrevComponent;
private javax.swing.JLabel lblTest;
private javax.swing.JScrollPane scpNextComponent;
private javax.swing.JTextArea txaNextComponent;
}

public class TestDropdownSubform extends Application {

@Override
public void start(Stage primaryStage) {
MainTestForm mtfMain = new MainTestForm();

mtfMain.setVisible(true);
}

/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}

}

我的问题是,我是否遗漏了一个细节,或者任何人都可以找到更好的方法来完成此任务吗?预先感谢您的建议。

编辑:将JComboBox声明为

JComboBox cboTest = new JComboBox<DimPanel>() {
private boolean layingOut = false;

@Override
public void doLayout(){
try{
layingOut = true;
super.doLayout();
}finally{
layingOut = false;
}
}

@Override
public Dimension getSize(){
Dimension dim = super.getSize();
if(!layingOut) {
dim.width = Math.max(dim.width, dpThis.getPreferredSize().width);
}
return dim;
}
};

固定下拉菜单的宽度。声明为

JComboBox cboTest = new JComboBox<testdropdownsubform.DicePanel>() {
private boolean layingOut = false;

@Override
public void doLayout(){
try{
layingOut = true;
super.doLayout();
}finally{
layingOut = false;
}
}

@Override
public Dimension getSize(){
Dimension dim = super.getSize();
if(!layingOut) {
Dimension dim2 = dpThis.getPreferredSize();
dim.width = Math.max(dim.width, dim2.width);
// dim.height = dim2.height;
}
return dim;
}

@Override
public DimPanel getPrototypeDisplayValue() {
DimPanel tmpPanel = new DimPanel();
if(isCalledFromComboPopup()) {
//
}
else {
Dimension r = dcbeEditor.getPreferredSize();
tmpPanel.setPreferredSize(r);
}
return tmpPanel;
}

/**
* Hack method to determine if called from within the combo popup UI.
*/
public boolean isCalledFromComboPopup() {
try {
final Throwable t = new Throwable();
t.fillInStackTrace();
StackTraceElement[] st = t.getStackTrace();
// look only at top 5 elements of call stack
int max = Math.min(st.length, 5);
for (int i=0; i<max; ++i) {
final String name = st[i].getClassName();
System.out.println(i + ") " + name);
return ((name != null) && name.contains("ComboPopup"));
}
} catch (final Exception e) {
// if there was a problem, assume not called from combo popup
}
return false;
}
};

修复了编辑器的大小但是现在下拉菜单是编辑器的宽度和高度。

最佳答案

所以,我最终走上了不同的轨道,在 JPanel 中使用 JTextFieldJButton 创建了我自己的伪组合框.我相信我已经很轻松地将结果泛化为四个相关类。首先,您需要一个 AbstractPopupPanel 的实现(如果您正在使用它,它可以很方便地加载到 NetBeans 设计器中):

package complexcombobox;

/**
*
* @author MaskedCoder
*
* @param E - the object to be edited in the panel
*/
public abstract class AbstractPopupPanel<E> extends javax.swing.JPanel {

/**
* Creates new form PopupPanel
*/
public AbstractPopupPanel() {
initComponents();
}

public abstract boolean isChanged();

public abstract E getValue();

public abstract void setValue(E newValue);

private void initComponents() {
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
}
}

创建令您满意后,我们需要将其放置在弹出菜单中:

package complexcombobox;

import javax.swing.JPopupMenu;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

/**
*
* @author MaskedCoder
*
* @param E - the object to be edited
* @param P - the extension of AbstractPopupPanel that will display the object as you wish
*/
public class ComplexPopup<E, P extends AbstractPopupPanel<E>> extends JPopupMenu {

/*
* Interface to notify user of editing
*/
public interface EditListener<E> {
// return the object's value to be edited.
// if the user returns null, the existing Dice is used.
public E beforeEdit();

// receives the new value
// called *only* when the object has actually changed.
public void afterEdit(E newValue);
}

/*
*internal variables
*/
private P thisPanel;
private EditListener<E> userListener;
// private Class<E> eClass;
// private Class<P> pClass;
private PopupMenuListener myPopupListener = new PopupMenuListener() {

@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
if(userListener != null) {
E tmpSize = userListener.beforeEdit();
if(tmpSize != null) thisPanel.setValue(tmpSize);
}
}

@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
if(userListener != null) {
// if(thisPanel.isChanged())
userListener.afterEdit((E) thisPanel.getValue());
}
}

@Override
public void popupMenuCanceled(PopupMenuEvent e) {
popupMenuWillBecomeInvisible(e);
}
};

/*
* Constructors
*/

public ComplexPopup(E iniValue, P iniDropdownPanel, EditListener<E> iniListener) {
super();

init(iniValue, iniDropdownPanel, iniListener);
}

private void init(E iniValue, P iniDropdownPanel, EditListener<E> iniListener) {
thisPanel = iniDropdownPanel;
thisPanel.setValue(iniValue);
add(thisPanel);
userListener = iniListener;
this.addPopupMenuListener(myPopupListener);
}

/*
* Public Properties
*/
public E getValue() {
return (E) thisPanel.getValue();
}
public void setValue(E newObjectSize) {
thisPanel.setValue(newObjectSize);
}

public EditListener getUserListener() {
return userListener;
}

public void setEditListener(EditListener newListener) {
userListener = newListener;
}

/*
* functional extensions
*/
public void afterEdit(E newValue) {
if(userListener != null) {
if(thisPanel.isChanged())
userListener.afterEdit((E) thisPanel.getValue());
}
}
}

这会将表单放置在 JPopupMenu 中,并允许访问要编辑的对象以及编辑前后的通知。现在,我无法在不深入了解机制的情况下选择 JComboBox 界面,所以我捏造了组合框,正如我提到的:

package complexcombobox;

/**
*
* @author MaskedCoder
*
* @param <I> the Item (Object) to be edited
* @param <Q> the AbstractPopupPanel to be used to do the editing.
*/
public class ComplexComboBox<I, Q extends AbstractPopupPanel<I>> extends javax.swing.JPanel {
private ComplexPopup<I, Q> thePopup;
private ComplexPopup.EditListener<I> myListener = new ComplexPopup.EditListener<I>() {

@Override
public I beforeEdit() {
return null; // no changes so, just let it ride.
}

@Override
public void afterEdit(I newValue) {
txtEditor.setText(thePopup.getValue().toString());
}
};

/**
* Creates new form ObjectSizeComboBox
*/
public ComplexComboBox(I iniValue, Q iniPanel) {
initComponents();
thePopup = new ComplexPopup<I, Q>(iniValue, iniPanel, myListener);
}

public I getValue() {
return thePopup.getValue();
}

public void setValue(I newValue) {
thePopup.setValue(newValue);
}

private void initComponents() {

txtEditor = new javax.swing.JTextField();
btnShowPanel = new javax.swing.JButton();

setBackground(new java.awt.Color(255, 255, 255));
setMinimumSize(new java.awt.Dimension(40, 19));

txtEditor.setEditable(false);
txtEditor.setToolTipText("");
txtEditor.setOpaque(false);

btnShowPanel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/testpopupsubform/art/dropdownarrow.png"))); // NOI18N
btnShowPanel.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnShowPanelActionPerformed(evt);
}
});

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(txtEditor, javax.swing.GroupLayout.DEFAULT_SIZE, 115, Short.MAX_VALUE)
.addGap(1, 1, 1)
.addComponent(btnShowPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(btnShowPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(txtEditor)
);
}

private void btnShowPanelActionPerformed(java.awt.event.ActionEvent evt) {
thePopup.show(txtEditor, 0, txtEditor.getHeight());
}

private javax.swing.JButton btnShowPanel;
private javax.swing.JTextField txtEditor;
}

如果您使行高足够高,这似乎在表格的单元格编辑器中工作得很好。不过,这与常规的 JComboBox 编辑器没有什么不同:

package complexcombobox;

import java.awt.Component;
import javax.swing.AbstractCellEditor;
import javax.swing.JTable;
import javax.swing.table.TableCellEditor;

/**
*
* @author MaskedCoder
*
* @param <E> the Element (Object) to be edited
* @param <P> the AbstractPopupPanel to be used to do the editing.
*/
public class ComplexCellEditor<E, P extends AbstractPopupPanel<E>> extends AbstractCellEditor
implements TableCellEditor {
private ComplexComboBox<E, P> ComplexEditor;

/*
* Constructors
*/
public ComplexCellEditor(E iniValue, P iniPanel) {
super();

ComplexEditor = new ComplexComboBox<E, P>(iniValue, iniPanel);
}

/*
* AbstractCellEditor Extensions
*/
@Override
public boolean stopCellEditing() {
return super.stopCellEditing();
}

/*
* TableCellEditor Implementation
*/
@Override
public E getCellEditorValue() {
return ComplexEditor.getValue();
}

@Override
public Component getTableCellEditorComponent(JTable iniTable, Object iniValue, boolean isSelected, int row, int column) {
ComplexEditor.setValue((E) iniValue);

return ComplexEditor;
}
}

我不完全满意的三件事: - 我想从系统中获取 JComboBox 向下箭头图标,而不是依赖项目资源 - 我必须通过 AbstractPopupPanel 实例,这意味着编码人员必须自己创建面板,然后将其交给 ComplexComboBoxComplexCellEditor 的构造函数。我宁愿在内部创建面板,在 ComplexPopup 中并自己管理它。我在实例化通用构造函数时遇到了困难。直通确实允许编码人员进行更多控制,但我认为这不是必需的,我希望它至少是可选的。

我对泛型的了解并不高深,但这似乎可以解决问题。

关于java - JComboBox 下拉列表中的 JPanel 但不在编辑器中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31353247/

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