我在最近创建的java应用程序中遇到了上述问题。即使我清楚地将该字段设置为JPasswordField并试图用星号掩盖密码,我仍然面临这个问题。当我们编辑密码字段时,只有在您选择行时才会出现问题。例如,我连续有2列,如果我选择整行并尝试复制粘贴记事本中的行,则会出现密码。我是java编程世界的新手,如果有人可以提供帮助将会有很大的帮助。
答案 0 :(得分:3)
你想要的是相当合乎逻辑的。从表中复制粘贴数据时,应该尊重渲染。
标准复制操作将使用模型中可用的数据,其中密码以纯文本形式提供。我们可以开始讨论是否要让您的模型包含密码作为纯文本,而不应用任何哈希......但这不能回答您的问题。
对于您的问题,您应该修改JTable
的剪切/复制操作的行为。看看拖放Swing教程,更具体地说是Adding Cut, Copy and Paste section。不幸的是,我没有立即找到一个参考的例子。
修改强>
在下面找到一个JXTable
的示例,它使用渲染值进行复制操作(我没有复制粘贴导入)。关于代码的一点注意事项:
TableModel
及其元素相当愚蠢。为了避免过多的工作,我需要类似于我们真实产品的东西来复制一些代码SpeedStringValue
和AltitudeStringValue
类在返回StringValue
时违反null
接口。我懒得定义一个新接口,我在SwingX StringValue
上设置的DefaultTableRenderer
实例根据文档行为。我认为,将StringValue
个实例分别用于将特定类转换为String
的知识是SwingX
TransferHandler
重用StringValue
逻辑来创建仅包含Table
个实例的String
,然后再回到默认的JTable
行为。这允许重用渲染器中实现的逻辑,并允许复制视觉值而不是模型值。我不确定这是否是最好的解决方案,但它确实有效。如果类似的行为在SwingX
中是标准的,那就好了,因为它们已经有了基础设施代码缺少评论,因为它已经足够长了。如果有什么不清楚的地方,请发表评论,我会尽力澄清
public class TableTransferHandlerDemo {
public static void main( String[] args ) throws InvocationTargetException, InterruptedException {
EventQueue.invokeAndWait( new Runnable() {
public void run() {
JFrame frame = new JFrame( "TestFrame" );
JPanel contentPane = new JPanel( new BorderLayout( ) );
contentPane.add( createTable(), BorderLayout.CENTER );
frame.getContentPane().add( contentPane );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.pack();
frame.setVisible( true );
}
} );
}
private static CompositeStringValue createStringValue() {
CompositeStringValue stringValue = new CompositeStringValue();
stringValue.delegates.add( new AltitudeStringValue() );
stringValue.delegates.add( new SpeedStringValue() );
return stringValue;
}
public static JXTable createTable(){
final JXTable table = new JXTable( );
table.setSelectionMode( ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
table.setModel( createTableModel() );
CompositeStringValue stringValue = createStringValue();
table.setDefaultRenderer( Object.class, new DefaultTableRenderer( stringValue ) );
table.setTransferHandler( new TableTransferHandler( table, stringValue ) );
//make sure ctrl-c triggers a copy
InputMap inputMap = table.getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
inputMap.put( KeyStroke.getKeyStroke( KeyEvent.VK_C, InputEvent.CTRL_MASK ), "copyAction" );
table.getActionMap().put( "copyAction", new AbstractAction() {
public void actionPerformed( ActionEvent e ) {
ActionEvent event = new ActionEvent( table, e.getID(), e.getActionCommand(), e.getWhen(), e.getModifiers() );
TransferHandler.getCopyAction().actionPerformed( event );
}
} );
return table;
}
public static class Speed{
public double speed;
public String unit = "km/h";
public Speed( double speed ){ this.speed = speed;}
}
public static class Altitude{
public double altitude;
public String unit = "m";
public Altitude( double altitude ){ this.altitude = altitude; }
}
public static class SpeedStringValue implements StringValue{
public String getString( Object o ) {
if ( o instanceof Speed ){
return ( ( Speed ) o ).speed + ( ( Speed ) o ).unit;
}
return null;
}
}
public static class AltitudeStringValue implements StringValue{
public String getString( Object o ) {
if ( o instanceof Altitude ){
return ( ( Altitude ) o ).altitude + ( ( Altitude ) o ).unit;
}
return null;
}
}
public static class CompositeStringValue implements StringValue{
public List<StringValue> delegates = new ArrayList<StringValue>( );
public String getString( Object o ) {
for ( StringValue stringValue : delegates ) {
String string = stringValue.getString( o );
if ( string != null ) return string;
}
return o != null ? o.toString() : "null";
}
}
public static TableModel createTableModel(){
return new DefaultTableModel(
new Object[][]{ new Object[]{ new Speed( 10 ), new Altitude( 100 )},
new Object[]{ new Speed( 20 ), new Altitude( 200 ) }},
new Object[]{"Speed", "Altitude"} );
}
public static class TableTransferHandler extends TransferHandler{
private JXTable table;
private StringValue stringValue;
public TableTransferHandler( JXTable aTable, StringValue aStringValue ) {
table = aTable;
stringValue = aStringValue;
}
@Override
public void exportToClipboard( JComponent aComponent, Clipboard aClipboard, int aAction ) throws IllegalStateException {
JTable table = createTable();
table.getTransferHandler().exportToClipboard( table, aClipboard, aAction );
}
@Override
public void exportAsDrag( JComponent aComponent, InputEvent aEvent, int aAction ) {
JTable table = createTable();
table.getTransferHandler().exportAsDrag( table, aEvent, aAction );
}
@Override
protected Transferable createTransferable( JComponent c ) {
//this transfer handler should not create any transferables
return null;
}
/**
* Create a table, representing the JXTable containing only Strings
*/
private JTable createTable() {
JTable table = new JTable( new StringTableModel( this.table, stringValue ) );
table.setSelectionModel( this.table.getSelectionModel() );//make sure the selection is synced
return table;
}
}
private static class StringTableModel extends AbstractTableModel {
private JXTable delegateTable;
private StringValue stringValue;
private StringTableModel( JXTable aTable, StringValue aStringValue ) {
delegateTable = aTable;
stringValue = aStringValue;
}
public int getRowCount() {
return delegateTable.getModel().getRowCount();
}
public int getColumnCount() {
return delegateTable.getModel().getColumnCount();
}
public Object getValueAt( int aRowIndex, int aColumnIndex ) {
return stringValue.getString( delegateTable.getValueAt( aRowIndex, aColumnIndex ) );
}
}
}
答案 1 :(得分:2)
像其他人一样玩猜谜游戏(描述是......缺乏; - )
因此,假设一个包含用户名和密码的两列tableModel,分别在JTable中呈现,拖拽已启用为true且默认为transferHandler。假设JTable中的密码呈现以某种方式被“屏蔽”,但在c&amp; p中显示为明文。
@Robin已经检测到了根本原因:默认的transferHandler只是使用getValueAt(...)。toString()来创建transferable。这导致泄露密码字符串,它就是存储在模型中的内容。
一个简单的出路(与更好的Transferhandler相反,@ Robin已经提到过:使用呈现的值而不是toString。请注意自己:SwingX的文件任务)for for not 存储普通密码但是包装对象:
public class Password {
private final String password;
public Password(String password) {
this.password = password;
}
// api as needed to make it worthwile ...
public boolean isValid(String password) {
...
}
// for the sake of c&p, override the toString
// for the lazy, this is the string rep used by the default renderer
@Override
public String toString() {
return "******************";
}
}
附录(这是特定的SwingX,将我的评论扩展到@ Robin的例子)
实际上我喜欢这种方法作为复制的快速解决方案。只是“修复”包装模型以充分利用当前的api,即将table.getStringAt(...)用于String表示。有了这个,就没有必要在几个地方传递StringValue,内部会在适当的时候处理它。
private static class StringTableModel extends AbstractTableModel {
private JXTable delegateTable;
private StringTableModel(JXTable aTable) {
delegateTable = aTable;
}
@Override
public int getRowCount() {
return delegateTable.getRowCount();
}
@Override
public int getColumnCount() {
return delegateTable.getColumnCount();
}
@Override
public Object getValueAt(int aRowIndex, int aColumnIndex) {
return delegateTable.getStringAt(aRowIndex, aColumnIndex);
}
}
在框架层面上,SwingX应该支持WYSIWYE(你看到的是什么导出),就像它的其他WYSIWYX:X = M匹配,X = S for sort, X = F表示滤波器。提升issue 1477 in the SwingX issue tracker
答案 2 :(得分:1)
您是否尝试在密码列上禁用单元格编辑?
您可以通过扩展JTable类并使用您自己的实现替换 isCellEditable 函数来实现此目的。
答案 3 :(得分:1)
使用显示here的示例,我可以粘贴密码,但不能复制或剪切密码。无论echoChar
设置的可见性如何,都会发生这种情况。你看到不同的结果吗?