2012-03-12 10 views
7

मेरे पास एक जावा स्विंग एप्लिकेशन है जिसमें टेक्स्ट नियंत्रण वाले बाल संवाद होते हैं। और समस्या यह है कि जब आप बाल संवाद में कीबोर्ड लेआउट बदलते हैं, तो संवाद बंद होने के बाद यह ठीक से बदल जाता है।स्विंग ऐप में कीबोर्ड लेआउट को संरक्षित करना?

मुझे स्विच करने के बाद रहने के लिए केबोर्ड लेआउट की आवश्यकता है चाहे इसे मुख्य फ्रेम में या बाल फ्रेम में स्विच किया गया हो।

import javax.swing.*; 
import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

public class InheritInputContext { 

    public static void main(String[] arg) { 
     final MainFrame mainFrame = new MainFrame(); 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       mainFrame.setPreferredSize(new Dimension(300, 400)); 
       mainFrame.pack(); 
       mainFrame.setLocationRelativeTo(null); 
       mainFrame.setVisible(true); 
      } 
     }); 

    } 
} 


class MainFrame extends JFrame { 

    MainFrame() { 
     setLayout(new BorderLayout()); 
     JTextArea textArea = new JTextArea(); 
     add(textArea, BorderLayout.CENTER); 

     JButton dialogBtn = new JButton("Dialog"); 
     add(dialogBtn, BorderLayout.SOUTH); 
     dialogBtn.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       ChildDialog cd = new ChildDialog(MainFrame.this); 
       cd.setPreferredSize(new Dimension(200, 200)); 
       cd.setLocationRelativeTo(MainFrame.this); 
       cd.pack(); 
       cd.setVisible(true); 
      } 
     }); 
    } 
} 


class ChildDialog extends JDialog { 

    ChildDialog(Window w) { 
     super(w); 
     JTextArea textArea = new JTextArea(); 
     getContentPane().add(textArea); 
    } 
} 
+1

क्या आप ऑपरेटिंग सिस्टम के कीबोर्ड लेआउट के बारे में बात कर रहे हैं? यहां थोड़ा उलझन में है। –

उत्तर

2

ठीक है, मैं तो बस इस समाधान के साथ बसे:

इस तरह जावा टूलकिट करने के लिए एक श्रोता जोड़ा main() प्रणाली में:

AWTEventListener awtWindowListener = new AWTEventListener() { 
    @Override 
    public void eventDispatched(AWTEvent event) { 
     if (event instanceof WindowEvent) { 
      if (WindowEvent.WINDOW_CLOSED == event.getID() 
        || WindowEvent.WINDOW_CLOSING == event.getID()) { 
       Window child = ((WindowEvent) event).getWindow(); 
       Window parent = SwingUtilities.getWindowAncestor(child); 
       if (parent == null) return; 
       InputContext childIC = child.getInputContext(); 
       parent.getInputContext().selectInputMethod(childIC.getLocale()); 
      } 
     } 

    } 
}; 

Toolkit.getDefaultToolkit().addAWTEventListener(awtWindowListener, AWTEvent.WINDOW_EVENT_MASK); 

यह रूप में माता पिता के खिड़की के साथ उत्पन्न सभी बच्चे संवादों पर काम करता है कन्स्ट्रक्टर पैरामीटर। करीबी घटना पर बाल संवाद के इनपुटकॉन्टेक्स्ट से लोकेल को इसकी मूल विंडो के इनपुटकॉन्टेक्स्ट में रखा जाता है।

हालांकि कुछ बेहतर तरीका हो सकता है।

1

तुम सिर्फ एक रास्ता किसी भी लेआउट परिवर्तन विश्व स्तर पर आपके आवेदन को प्रभावित करने के लिए के लिए देख रहे:

यहाँ एक SSCCE है कि समस्या को दिखाता है?

यदि ऐसा है, तो एक कस्टम श्रोता बनाने के लिए एक दृष्टिकोण है, लेआउट परिवर्तन के बारे में देखभाल करने वाले विभिन्न घटक ऐसे घटनाओं में अपनी रुचि पंजीकृत करते हैं, और उसके बाद एक परिवर्तन लेआउट ईवेंट को बंद कर देते हैं जो सभी घटकों में परिवर्तन को ट्रिगर करता है उनमें से किसी एक में परिवर्तन।

ऐसा करने का एक और तरीका किसी ऑब्जेक्ट में लेआउट गुणों को संग्रहीत करेगा जो किसी भी घटक के लिए सुलभ है, और उन्हें टाइमर के माध्यम से समय-समय पर अपना लेआउट अपडेट कर देगा। हालांकि, यह कम वांछनीय होगा, क्योंकि ऑपरेशन के "ईवेंट पर केवल अपडेट" मोड बनाम बहुत सारे अनावश्यक अपडेट होंगे। मैं अनुमान लगा रहा हूं कि आपके आवेदन के उपयोगकर्ता अपने कीबोर्ड लेआउट को प्रति सत्र एक या दो बार से अधिक नहीं बदलेंगे (जैसा कि हर 5 सेकंड के विपरीत है)?

ऐसा करने के लिए एक और, तीसरा तरीका यह है कि कीबोर्ड लेआउट सेटिंग्स को एप्लिकेशन स्तर पर संग्रहीत किया गया है, और स्टार्टअप पर लोड किया गया है। फिर, जब एक कीबोर्ड लेआउट परिवर्तन होता है, तो उपयोगकर्ता को वैश्विक स्तर पर परिवर्तनों के प्रभाव के लिए ऐप को पुनरारंभ करने के लिए संकेत दें।

+0

हां, मैं प्रत्येक नए संवाद में बार-बार लेआउट बदलने की आवश्यकता से बचने के लिए, एप्लिकेशन में किए गए किसी भी लेआउट परिवर्तन को संरक्षित करने का एक तरीका ढूंढ रहा हूं। अभी मैं प्रत्येक बच्चे फ्रेम – yggdraa

+0

के लिए अतिरिक्त कोड लिखने से बचने के लिए ऐप स्तर पर AWTEventListener का उपयोग करने का विकल्प तलाश रहा हूं, ऑन-टाइमर अपडेट प्रश्न से बाहर है, यह अधिभारित होगा। ऐप-रीलोड के लिए पूछना भी प्रश्न से बाहर है, उपयोगकर्ता को हर समय 2 भाषाओं के बीच बदलना होगा। – yggdraa

+0

मैंने नेटबीन और इंटेलिजिडा में भी देखा, वही बात है। आप सेटिंग्स खोलते हैं, उदाहरण के लिए, इनपुट भाषा बदलें, सेटिंग्स बंद करें और कीबोर्ड लेआउट उस चीज़ पर वापस लौटाता है जो पहले होता था। अन्य अनुप्रयोगों में (ब्राउज़र, mssql, नोटपैड) कीबोर्ड लेआउट का परिवर्तन पूरे ऐप पर लगातार होता है। – yggdraa

1

हां और नहीं: 13 मार्च के yggdraa के कोड ने विंडोज पर ठीक काम किया लेकिन लिनक्स पर असफल रहा।

लिनक्स के लिए कोई सार्वभौमिक समाधान नहीं हो सकता है: विंडोज़ 'GetKeyboardLayout() और ActiveateKeyboardLayout() जैसी कोई चीज नहीं है। हालांकि कुछ कॉन्फ़िगरेशन-निर्भर हैक्स संभव हो सकते हैं, जैसे xset (details here) के आउटपुट को पार्स करना और लेआउट को मजबूर करना, कहें, कुंजी अप/डाउन पर।

उपरोक्त उदाहरण में, ईवेंट डिस्प्लेटेड() में इनपुट चयन कोड बहुत देर हो जाता है - जब ओएस कीबोर्ड पहले ही सिस्टम-डिफ़ॉल्ट यूएस पर स्विच हो चुका है।

कुछ ब्रूट फोर्स प्रयासों ने या तो काम नहीं किया: फ़ील्ड के फोकस हैंडलर से myParticularJField.setLocale (myForcedLocale) तुरंत पहली कुंजी प्रेस पर पूर्ववत हो जाता है। शीर्ष-स्तर (जेएफआरएएम/जेडियलॉग) लोकेल को मजबूर करने के लिए वही।

अद्यतन:

हम उत्पादन में केवल Windows है तो लिनक्स के तहत यह काम कर रही है अव्यावहारिक है: बहुत अधिक प्रयास।

बस एक उपज के मामले में। यह सही ढंग से निर्धारित करता है कि कौन सा लेआउट वर्तमान में सक्रिय है: डिफ़ॉल्ट या वैकल्पिक ("स्थानीय")। यह कई विकल्प लेआउट के बीच भेद नहीं कर सकते हैं:

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 

public class LinuxKeyboardLayoutStatus { 

    public enum LayoutType { DEFAULT, LOCAL } 

    public LinuxKeyboardLayoutStatus.LayoutType getCurrentKeyboardLayoutType() throws IOException, InterruptedException { 
     String[] command = createCommand(); 
     Process p = Runtime.getRuntime().exec(command); 
     BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream())); 
     String l = r.readLine(); 
     r.close(); 
     p.waitFor(); 
     return decodeLayoutType(l); 
    } 

    protected String[] createCommand() { 
     return new String[] { "/bin/sh", "-c", "xset -q | grep LED | awk '{ print $10 }' | cut -c5" }; 
    } 

    protected LinuxKeyboardLayoutStatus.LayoutType decodeLayoutType(String commandOutput) { 
     return 
      commandOutput != null && !commandOutput.equals("0") ? LayoutType.LOCAL : LayoutType.DEFAULT; 
    } 

} 

अद्यतन:

उबंटू में, परिवर्तन वापस डिफ़ॉल्ट लेआउट के लिए एक्स खिड़की स्तर (DBus घटनाओं) पर होता है। एक वर्कअराउंड: प्रत्येक विंडो के लिए अलग-अलग लेआउट बंद करने के लिए: सेटिंग्स => कीबोर्ड => लेआउट, "प्रत्येक विंडो के लिए अलग लेआउट" अनचेक करें।

संबंधित मुद्दे