- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我想要的东西看起来比较简单,我也差不多了。这最终将用于扩展 TableCellEditor
,因此大小很重要。我想要的是这样的:
结合使用自定义 ComboBoxEditor
和 ListCellRenderer
我已经能够得到这样的东西:
有以下不便之处:
JComboBox
原始宽度的任何组件JComboBox
的高度为下拉列表中 JPanel
的高度我想让下拉列表保持可见,直到用户单击编辑器或 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
中使用 JTextField
和 JButton
创建了我自己的伪组合框.我相信我已经很轻松地将结果泛化为四个相关类。首先,您需要一个 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
实例,这意味着编码人员必须自己创建面板,然后将其交给 ComplexComboBox
或 ComplexCellEditor 的构造函数
。我宁愿在内部创建面板,在 ComplexPopup
中并自己管理它。我在实例化通用构造函数时遇到了困难。直通确实允许编码人员进行更多控制,但我认为这不是必需的,我希望它至少是可选的。
我对泛型的了解并不高深,但这似乎可以解决问题。
关于java - JComboBox 下拉列表中的 JPanel 但不在编辑器中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31353247/
我需要将文本放在 中在一个 Div 中,在另一个 Div 中,在另一个 Div 中。所以这是它的样子: #document Change PIN
奇怪的事情发生了。 我有一个基本的 html 代码。 html,头部, body 。(因为我收到了一些反对票,这里是完整的代码) 这是我的CSS: html { backgroun
我正在尝试将 Assets 中的一组图像加载到 UICollectionview 中存在的 ImageView 中,但每当我运行应用程序时它都会显示错误。而且也没有显示图像。 我在ViewDidLoa
我需要根据带参数的 perl 脚本的输出更改一些环境变量。在 tcsh 中,我可以使用别名命令来评估 perl 脚本的输出。 tcsh: alias setsdk 'eval `/localhome/
我使用 Windows 身份验证创建了一个新的 Blazor(服务器端)应用程序,并使用 IIS Express 运行它。它将显示一条消息“Hello Domain\User!”来自右上方的以下 Ra
这是我的方法 void login(Event event);我想知道 Kotlin 中应该如何 最佳答案 在 Kotlin 中通配符运算符是 * 。它指示编译器它是未知的,但一旦知道,就不会有其他类
看下面的代码 for story in book if story.title.length < 140 - var story
我正在尝试用 C 语言学习字符串处理。我写了一个程序,它存储了一些音乐轨道,并帮助用户检查他/她想到的歌曲是否存在于存储的轨道中。这是通过要求用户输入一串字符来完成的。然后程序使用 strstr()
我正在学习 sscanf 并遇到如下格式字符串: sscanf("%[^:]:%[^*=]%*[*=]%n",a,b,&c); 我理解 %[^:] 部分意味着扫描直到遇到 ':' 并将其分配给 a。:
def char_check(x,y): if (str(x) in y or x.find(y) > -1) or (str(y) in x or y.find(x) > -1):
我有一种情况,我想将文本文件中的现有行包含到一个新 block 中。 line 1 line 2 line in block line 3 line 4 应该变成 line 1 line 2 line
我有一个新项目,我正在尝试设置 Django 调试工具栏。首先,我尝试了快速设置,它只涉及将 'debug_toolbar' 添加到我的已安装应用程序列表中。有了这个,当我转到我的根 URL 时,调试
在 Matlab 中,如果我有一个函数 f,例如签名是 f(a,b,c),我可以创建一个只有一个变量 b 的函数,它将使用固定的 a=a1 和 c=c1 调用 f: g = @(b) f(a1, b,
我不明白为什么 ForEach 中的元素之间有多余的垂直间距在 VStack 里面在 ScrollView 里面使用 GeometryReader 时渲染自定义水平分隔线。 Scrol
我想知道,是否有关于何时使用 session 和 cookie 的指南或最佳实践? 什么应该和什么不应该存储在其中?谢谢! 最佳答案 这些文档很好地了解了 session cookie 的安全问题以及
我在 scipy/numpy 中有一个 Nx3 矩阵,我想用它制作一个 3 维条形图,其中 X 轴和 Y 轴由矩阵的第一列和第二列的值、高度确定每个条形的 是矩阵中的第三列,条形的数量由 N 确定。
假设我用两种不同的方式初始化信号量 sem_init(&randomsem,0,1) sem_init(&randomsem,0,0) 现在, sem_wait(&randomsem) 在这两种情况下
我怀疑该值如何存储在“WORD”中,因为 PStr 包含实际输出。? 既然Pstr中存储的是小写到大写的字母,那么在printf中如何将其给出为“WORD”。有人可以吗?解释一下? #include
我有一个 3x3 数组: var my_array = [[0,1,2], [3,4,5], [6,7,8]]; 并想获得它的第一个 2
我意识到您可以使用如下方式轻松检查焦点: var hasFocus = true; $(window).blur(function(){ hasFocus = false; }); $(win
我是一名优秀的程序员,十分优秀!