Una breve panoramica dei framework GUI per Java e la mia prima semplice applicazione GUI in Swing. Il processo di sviluppo di un semplice programma GUI in Java Un esempio di utilizzo di un pannello Swing JOptionPane trasparente


L'interfaccia grafica in Java ha attraversato un percorso di sviluppo e formazione molto spinoso. Per molto tempo è stato accusato di essere lento, avido di risorse di sistema e di funzionalità limitata.

JavaAWT

Il primo tentativo di Sun di creare una GUI per Java è stata la libreria A.W.T.(Abstract Window Toolkit) - un toolkit per lavorare con vari ambienti finestre. Sun ha creato un livello Java che chiama metodi dalle librerie scritte in C. I metodi della libreria AWT creano e utilizzano componenti grafici dell'ambiente operativo. Da un lato questo è positivo, poiché un programma Java è simile ad altri programmi all'interno dello stesso sistema operativo. Ma quando lo esegui su un'altra piattaforma, potrebbero esserci differenze nelle dimensioni dei componenti e dei caratteri che rovineranno l'aspetto del programma.

Per garantire la multipiattaforma A.W.T. Le interfacce di chiamata dei componenti sono state unificate, di conseguenza la loro funzionalità è stata leggermente ridotta. E il set di componenti si è rivelato piuttosto piccolo. Ad esempio, AWT non dispone di tabelle e i pulsanti non supportano la visualizzazione delle icone. Ancora il pacchetto java.awtè stato incluso in Java sin dalla sua prima versione e può essere utilizzato per creare GUI.

Quindi i componenti A.W.T. Non fanno alcun "lavoro". Si tratta semplicemente di un "wrapper Java" per i controlli del sistema operativo su cui girano. Tutte le richieste a questi componenti vengono reindirizzate al sistema operativo, che fa tutto il lavoro.

Risorse utilizzate A.W.T. tenta di rilasciare automaticamente. Ciò aggiunge un po' di complessità all'architettura e influisce sulle prestazioni. Sarà un po’ difficile scrivere qualcosa di serio usando AWT. Al giorno d'oggi viene utilizzato solo per le applet.

Concetti base dello SWING

Dopo A.W.T. Sun ha sviluppato una libreria di componenti grafici Oscillazione, scritto interamente in Java. Il 2D viene utilizzato per il rendering, il che porta con sé numerosi vantaggi. Il set di componenti standard supera significativamente AWT in varietà e funzionalità. Swing semplifica la creazione di nuovi componenti ereditando da quelli esistenti e supporta stili e skin diversi.

Creatori di una nuova libreria di interfacce utente Oscillazione Non hanno “reinventato la ruota” e hanno scelto AWT come base per la loro biblioteca. Naturalmente, non stavamo parlando dell'utilizzo di specifici componenti AWT pesanti (rappresentati dalle classi Button, Label e simili). Solo i componenti leggeri fornivano il grado di flessibilità e controllabilità richiesto. Il diagramma di ereditarietà mostra la relazione tra AWT e Swing.

La differenza più importante Oscillazione di AWT è che i componenti Swing non sono affatto accoppiati al sistema operativo e sono quindi molto più stabili e veloci. Questi componenti sono chiamati pesi leggeri in Java e comprendere i principi di base del loro funzionamento contribuirà notevolmente a spiegare come funziona Swing.

Contenitori battenti di altissimo livello

Per creare un'applicazione GUI, è necessario utilizzare componenti speciali della libreria Swing chiamati contenitori di livello superiore. Sono finestre del sistema operativo che ospitano componenti dell'interfaccia utente. I contenitori di livello superiore includono le finestre JFrame e JWindow, la finestra di dialogo JDialog e l'applet JApplet (che non è una finestra, ma è progettata anche per visualizzare l'interfaccia nel browser che avvia questa applet). I contenitori di livello superiore di Swing sono componenti pesanti e rappresentano l'eccezione alla regola generale. Tutti gli altri componenti Swing sono leggeri.

Semplice Oscillazione esempio di creazione di un'interfaccia a finestra JFrame.

Importa java.awt.Dimension; importa javax.swing.JFrame; importa javax.swing.JLabel; public class JFrameTest ( public static void createGUI() ( JFrame frame = new JFrame("Test frame"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JLabel label = new JLabel("Test label"); frame.getContentPane(). add(label); frame.setPreferredSize(new Dimension(200, 100)); frame.pack(); frame.setVisible(true); ) public static void main(String args) ( JFrame.setDefaultLookAndFeelDecorated(true); javax. swing.SwingUtilities.invokeLater(new Runnable() ( public void run() ( createGUI(); ) )); ) )

Costruttore JFrame() senza parametri crea una finestra vuota. Costruttore JFrame(Titolo stringa) crea una finestra vuota con il titolo titolo. Per creare un programma semplice con una finestra vuota, è necessario utilizzare i seguenti metodi:

  • setSize(int larghezza, int altezza) - determina la dimensione della finestra;
  • setDefaultCloseOperation(int operazione) - definisce l'azione al termine del programma;
  • setVisible(boolean visibile) - rende visibile la finestra.

Se non definisci le dimensioni di una finestra, avrà altezza zero, qualunque cosa contenga. Le dimensioni della finestra comprendono non solo l'area “di lavoro”, ma anche i bordi e la barra del titolo.

Il metodo setDefaultCloseOperation specifica l'azione da eseguire quando "il programma esce". Per fare ciò, dovresti passare la costante EXIT_ON_CLOSE, descritta nella classe JFrame, come parametro dell'operazione.

Per impostazione predefinita, la finestra viene creata invisibile. Per visualizzare la finestra sullo schermo, viene chiamato il metodo setVisible con il parametro true. Se chiamata con il parametro false, la finestra diventerà invisibile.

GUI altalena Java esempio di creazione di una finestra JFrameè presentato nella figura seguente.

Per connettere la biblioteca Oscillazione l'applicazione deve importare la libreria javax.swing.

Ogni volta che viene creato un contenitore di primo livello, sia esso una normale finestra, una finestra di dialogo o un'applet, a pannello radice JRootPane. I contenitori di primo livello di Swing garantiscono che altri componenti non possano uscire dal JRootPane.

Pale radicale JRootPane aggiunge la proprietà "profondità" ai contenitori, fornendo la possibilità non solo di posizionare i componenti uno sopra l'altro, ma anche, se necessario, di cambiarne la posizione, aumentare o diminuire la profondità dei componenti. Questa funzionalità è necessaria quando si crea un'applicazione multi-documento. Oscillazione, in cui le finestre rappresentano componenti leggeri posizionati uno sopra l'altro, nonché menu a discesa (contestuali) e descrizioni comandi.

La figura seguente mostra chiaramente la struttura del pannello radice JRootPane.

Pannello radice JRootPaneè un contenitore ereditato dalla classe base Swing JComponent. In questo contenitore, uno speciale gestore di layout, implementato nella classe interna RootPaneLayout, è responsabile della disposizione dei componenti. Questo gestore del layout è responsabile di garantire che tutte le parti componenti del pannello principale siano posizionate come dovrebbero: un pannello a più livelli occupa l'intero spazio della finestra; il suo layer FRAME_CONTENT_LAYER contiene la barra dei menu e il pannello dei contenuti, e soprattutto c'è un pannello trasparente.

Tutti i componenti del pannello principale JRootPane possono essere ottenuti o modificati. Per fare ciò, ha una serie di metodi get/set. A livello di programmazione JRootPane può essere ottenuto utilizzando il metodo getRootPane().

Oltre ai contenitori di livello superiore, il pannello root viene utilizzato nelle finestre JInternalFrame interne create in applicazioni multi-documento e posizionate sul "desktop" JDesktopPane. Ciò consente di dimenticare il fatto che queste finestre sono normali componenti leggeri e di lavorare con esse come se fossero veri e propri contenitori di primo livello.

JLayeredPane

Alla base del pannello radice (contenitore) si trova il cosiddetto pannello multistrato JLayeredPane, occupando tutto lo spazio disponibile del contenitore. È in questo pannello che si trovano tutte le altre parti del pannello principale, inclusi tutti i componenti dell'interfaccia utente.

JLayeredPane utilizzato per aggiungere una proprietà di profondità al contenitore. Cioè, un pannello multistrato consente di organizzare una terza dimensione nel contenitore, lungo la quale si trovano gli strati del componente. In un contenitore normale, la posizione di un componente è determinata da un rettangolo che mostra la parte del contenitore occupata dal componente. Quando si aggiunge un componente ad un pannello a strati, è necessario specificare non solo il rettangolo che occuperà il componente, ma anche il livello in cui verrà posizionato. Lo strato in un pannello sandwich è identificato da un numero intero. Più alto è il numero che definisce uno strato, più in alto si trova lo strato.

Il primo componente aggiunto al contenitore viene classificato più in alto rispetto ai componenti aggiunti successivamente. Molto spesso lo sviluppatore non si occupa della posizione dei componenti. Quando si aggiungono componenti, la loro posizione cambia automaticamente. Tuttavia, un pannello multistrato consente di modificare dinamicamente la posizione dei componenti, dopo che sono stati aggiunti al contenitore.

Le funzionalità dei pannelli laminati sono ampiamente utilizzate da alcuni componenti Oscillazione. Sono particolarmente importanti per applicazioni multi-documento, descrizioni comandi e menu. Multidocumento Oscillazione le applicazioni utilizzano un contenitore speciale JDesktopPane("desktop"), ereditato da JLayeredPane, che ospita le finestre interne a battente. Le funzioni più importanti di un'applicazione multi-documento - posizionare la finestra "attiva" sopra le altre, minimizzare le finestre, trascinarle - sono fornite dai meccanismi del pannello a strati. Il vantaggio principale dell'utilizzo di un pannello a più livelli per descrizioni comandi e menu è che funzionano più velocemente. Invece di creare una nuova finestra pesante per ogni descrizione comando o menu che si trova sopra il componente che ha richiesto la descrizione comando o il menu, Oscillazione crea un componente veloce e leggero. Questo componente è posizionato abbastanza in alto nel pannello a strati sopra la pila di tutti gli altri componenti e viene utilizzato per visualizzare una descrizione comando o un menu.

Il pannello multistrato consente di organizzare un numero illimitato di strati. Struttura JLayeredPane comprende diversi strati standard, utilizzati da tutti i componenti Swing, che garantiscono il corretto funzionamento di tutti i meccanismi del pannello multistrato. I livelli JLayeredPane standard sono mostrati nella figura seguente.

Il livello Default viene utilizzato per ospitare tutti i componenti normali che vengono aggiunti al contenitore. Questo livello ospita le finestre interne delle applicazioni multi-documento.

Il livello Tavolozza è progettato per ospitare finestre con una serie di strumenti, che solitamente si sovrappongono ad altri elementi dell'interfaccia. Puoi creare tali finestre utilizzando JDesktopPane, che le posiziona su questo livello.

Il livello Modale doveva ospitare finestre di dialogo modali leggere. Tuttavia, tali finestre di dialogo non sono ancora implementate, quindi questo livello non è attualmente utilizzato in Swing.

Il livello più comunemente utilizzato per posizionare menu a comparsa e descrizioni comandi.

Lo strato più alto. Progettato per operazioni di trascinamento della selezione che dovrebbero essere chiaramente visibili nell'interfaccia del programma.

Un piccolo esempio di JLayeredPane con un pannello a livelli mostra come aggiungere componenti a diversi livelli e come i livelli sono impilati uno sopra l'altro:

Importa javax.swing.*; importa java.awt.*; // classe per disegnare due tipi di figure con testo class Figure extends JComponent ( private static final long serialVersionUID = 1L; private Color color; private int type; private String text; // parametri: colore e tipo di figura Figure(Color color, int tipo, String testo) ( this.color = color; this.type = type; this.text = text; setOpaque(false); ) public void paintComponent(Graphics g) ( // disegna la figura g.setColor(color) ; switch (tipo ) ( case 0: g.fillOval(0, 0, 90, 90); break; case 1: g.fillRect(0, 0, 130, 80); break; ) g.setColor(Color.giallo ); g. drawString(text, 10, 35); ) ) public class JLayeredPaneTest estende JFrame ( private static final long serialVersionUID = 1L; public JLayeredPaneTest() ( // crea una finestra super("Esempio LayeredTest"); // esci alla chiusura della finestra setDefaultCloseOperation( EXIT_ON_CLOSE); // definizione di un pannello multistrato JLayeredPane lp = getLayeredPane(); // creazione di tre figure Figura figure1 = new Figure(Color.red , 0, "Figure popup"); Figura figura2 = nuova Figura(Color.blue, 0, "Figura 1"); Figura figura3 = nuova Figura(Color.cyan, 1, "Figura 2"); // determinazione della posizione delle figure nella finestra figure1.setBounds(10, 40, 120, 120); figura2.setBounds(60, 120, 160, 180); figura3.setBounds(90, 55, 250, 180); // aggiunta di forme a diversi livelli lp.add(figure1, JLayeredPane.POPUP_LAYER); lp.add(figura2, JLayeredPane.PALETTE_LAYER); lp.add(figura3, JLayeredPane.PALETTE_LAYER); // modifica la posizione di una delle figure lp.setPosition(figure3, 0); // determinazione della dimensione e apertura della finestra setSize(280, 250); setVisible(vero); ) public static void main(String args) ( JFrame.setDefaultLookAndFeelDecorated(true); new JLayeredPaneTest(); ) )

L'esempio crea una piccola finestra JFrame e diversi componenti Figura vengono aggiunti al pannello a strati. Per ottenere un pannello a più livelli in qualsiasi contenitore Swing di primo livello, basta chiamare il metodo getLayeredPane().

La classe ausiliaria Figure eredita le proprietà della classe base JComponent e consente di disegnare due tipi di forme (cerchi e rettangoli) in colori diversi. I parametri per disegnare le figure sono impostati nel costruttore della classe.

Quando si definisce un'interfaccia, vengono create tre forme di colori diversi (due cerchi e un rettangolo). Il cerchio viene posizionato nel livello POPUP_LAYER e i rettangoli vengono posizionati nel livello PALETTE_LAYER. Quando posizioni i componenti, specifichi le loro coordinate assolute dello schermo perché i normali gestori di layout non funzionano in un pannello a più livelli.

Infine, la posizione di uno dei rettangoli viene modificata in modo che sia il primo nel livello, sebbene originariamente fosse aggiunto per secondo. Quando avvii l'applicazione, vedrai che il pannello a strati funziona e dispone ordinatamente i componenti in base ai loro livelli e posizioni.

Nelle applicazioni convenzionali, il pannello sandwich viene raramente utilizzato direttamente, in cui svolge le sue funzioni in modo invisibile. Tuttavia, a volte aiuta a creare effetti sorprendenti e interfacce insolite, consentendo, ad esempio, di posizionare animazioni o video sopra componenti ordinari, senza richiedere sforzi e trucchi sovrumani da parte dello sviluppatore.

ContenutoPane

Riquadro dei contenuti ContentPane è la parte successiva del riquadro principale, utilizzata per ospitare i componenti dell'interfaccia utente del programma. ContenutoPane occupa la maggior parte dello spazio di un pannello a più livelli (ad eccezione dello spazio occupato dalla barra dei menu). Per evitare che il pannello del contenuto oscuri i componenti che vengono successivamente aggiunti alla finestra, il pannello a strati li posiziona in uno speciale livello molto basso chiamato FRAME_CONTENT_LAYER, numerato -30000.

È possibile accedere al pannello dei contenuti utilizzando il metodo getContentPane() classe JFrame. Utilizzando il metodo add(Component componente), puoi aggiungervi qualsiasi elemento di controllo. Sostituire ContenutoPane con qualsiasi altro pannello di tipo JPanel è possibile utilizzare il metodo setContentPane()

Esempio di aggiunta di un pulsante al pannello dei contenuti:

JButton nuovoButton = nuovo JButton(); getContentPane().add(newButton);

Di conseguenza, otteniamo una finestra con un pulsante. Il pulsante occupa l'intera area disponibile della finestra. Questo effetto non è utile in tutti i programmi, quindi è necessario utilizzare diversi modi per disporre gli elementi sul pannello.

Il pannello dei contenuti può essere completamente sostituito. Considera quanto segue Oscillazione esempio di utilizzo del pannello dei contenuti ContenutoPane.

Importa javax.swing.*; public class ContentPaneReplace estende JFrame ( private static final long serialVersionUID = 1L; public ContentPaneReplace() ( super("Test ContentPane"); setDefaultCloseOperation(EXIT_ON_CLOSE); // Crea un pannello con due pulsanti JPanel content = new JPanel(); content. add (new JButton("Family")); content.add(new JButton("School")); // Sostituzione del pannello dei contenuti setContentPane(contents); // Determinazione della dimensione della finestra setSize(200, 100); // Apertura della finestra setVisible (true); ) public static void main(String args) ( JFrame.setDefaultLookAndFeelDecorated(true); new ContentPaneAdd(); ) )

L'esempio crea una piccola finestra e un pannello con due pulsanti, che è then setContentPane() sostituisce il pannello del contenuto della finestra. Pertanto, è stata utilizzata una sostituzione invece di un'aggiunta più semplice, chiamando il metodo add(). L'interfaccia della finestra è mostrata nello screenshot seguente.

Pannello dei contenuti ContenutoPane in sé non è niente di speciale. Devi solo ricordare che i componenti vengono aggiunti appositamente ad esso.

JOptionPane trasparente

Pannello trasparente JOptionPane posizionato come pannello radice sopra tutti gli elementi del pannello multistrato. Il posizionamento di JOptionPane è controllato dal pannello principale, che posiziona il pannello trasparente sopra il pannello a strati in modo che copra completamente l'intera area della finestra, inclusa l'area occupata dalla barra dei menu.

JOptionPane Viene utilizzato raramente nelle applicazioni, quindi per impostazione predefinita il pannello root lo rende invisibile, riducendo il carico sul sistema di disegno. Una cosa da tenere a mente è che se rendi visibile un pannello trasparente, devi essere sicuro che sia trasparente (la sua proprietà opaque è impostata su false) perché altrimenti oscurerà tutti gli altri elementi del pannello root e il resto l'interfaccia sarà invisibile.

In quali casi è possibile utilizzare un pannello trasparente? JOptionPane? Con il suo aiuto, puoi identificare le funzioni dell'applicazione che richiederebbero uno sforzo serio per essere implementate da zero. Il pannello trasparente può essere adattato per il test automatizzato dell'interfaccia utente. Gli eventi in esso sintetizzati consentono di tenere traccia dei risultati intermedi del debug. A volte questo approccio è molto più efficace dei test manuali.

Pannello trasparente JOptionPane può essere utilizzato per una bella animazione da "galleggiare" sopra tutti i componenti, inclusa la barra dei menu, o per intercettare eventi se alcuni di essi devono essere elaborati prima di essere inviati alla parte principale dell'interfaccia utente.

Esempio di utilizzo di uno Swing JOptionPane trasparente:

// Utilizzando un pannello trasparente JOptionPane import java.awt.Dimension; importa java.awt.Font; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; importa javax.swing.JDialog; importa javax.swing.JFrame; importa javax.swing.JLabel; importa javax.swing.JOptionPane; importa javax.swing.UIManager; public class JOptionPaneTest estende JFrame ( private static final long serialVersionUID = 1L; public static final Font FONT = new Font("Verdana", Font.PLAIN, 11); public static void createGUI() ( JFrame frame = new JFrame("Test JOptionPane "); frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); frame.addWindowListener(new WindowListener() ( public void windowActivated(evento WindowEvent) () public void windowClosed(evento WindowEvent) () public void windowDeactivated(evento WindowEvent) () public void windowDeiconified(evento WindowEvent) () public void windowIconified(evento WindowEvent) () public void windowOpened(evento WindowEvent) () public void windowClosing(evento WindowEvent) ( Opzioni oggetto = ( "Sì", "No!" ); int rc = JOptionPane.showOptionDialog(event.getWindow(), "Chiudi finestra?", "Conferma", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, opzioni, opzioni); if (rc == 0) ( event.getWindow().setVisible (falso); System.exit(0); ) ) )); Etichetta JLabel = new JLabel("Usa il pannello trasparente quando chiudi la finestra"); frame.getContentPane().add(etichetta); frame.setPreferredSize(nuova dimensione(350, 80)); frame.pacco(); frame.setLocationRelativeTo(null); frame.setVisible(vero); ) public static void main(String args) ( javax.swing.SwingUtilities.invokeLater(new Runnable() ( public void run() ( UIManager.put("Button.font", FONT); UIManager.put("Label.font ", FONT); JFrame.setDefaultLookAndFeelDecorated(true); JDialog.setDefaultLookAndFeelDecorated(true); createGUI(); ) )); ) )

Se passi una costante al metodo setDefaultCloseOperation JFrame.EXIT_ON_CLOSE, quindi quando la finestra verrà chiusa, l'applicazione smetterà di funzionare. Nell'esempio, a questo metodo viene passata una costante JFrame.DO_NOTHING_ON_CLOSE in modo che non accada nulla quando la finestra è chiusa. L'applicazione nell'esempio viene chiusa dal listener JFrame WindowListener nel metodo finestraChiusura. Quando una finestra viene chiusa, il metodo windowClosing viene chiamato con il parametro evento WindowEvent, che nello Swing JOptionPane trasparente apre una finestra di dialogo di conferma.

La schermata seguente mostra due finestre dell'applicazione. Finestra principale in alto. Quando chiudi questa finestra, si apre la finestra di dialogo di conferma dell'intento inferiore.

Barra dei menu JMenuBar

Una delle caratteristiche importanti dell'utilizzo di JRootPane in Swing è la necessità di posizionare una barra dei menu nella finestra JMenuBar. Non è possibile creare un'applicazione seria senza una sorta di menu per accedere alle funzioni del programma. La libreria Swing offre eccellenti funzionalità per la creazione di menu JMenuBar intuitivi che sono anche componenti leggeri.

Barra dei menu JMenuBarè posizionato in un pannello multistrato in un livello speciale FRAME_CONTENT_LAYER e occupa un piccolo spazio nella parte superiore della finestra. La lunghezza della barra dei menu è uguale alla dimensione della finestra. La larghezza della barra dei menu dipende dai componenti che contiene.

Il pannello principale assicura che il pannello del contenuto e la barra dei menu JMenuBar non si è sovrapposto. Se non è necessaria una barra dei menu, il pannello principale utilizza tutto lo spazio per ospitare il pannello dei contenuti.

Esempi di altalena

I codici sorgente degli esempi discussi nel testo della pagina possono essere scaricati.

Immaginiamo di averti stancato parecchio parlando continuamente di programmi per inviare messaggi di testo alla console. In questa lezione questa “noiosa” serie di esempi verrà finalmente interrotta: mostreremo come si creano le finestre in Java e vedrete che si tratta di un compito semplice. Ecco il nostro codice (inizieremo a discuterne nella prossima lezione, perché ha tantissime funzionalità che devi davvero conoscere):

importa java.awt.*;

importa javax.swing.*;

la classe pubblica MoneyForNothing estende JFrame (

// Costruttore

public MoneyForNothing() (

setTitle("Benvenuto in Money for Nothing");

setSize(nuova dimensione(600, 400));

setDefaultCloseOperation(EXIT_ON_CLOSE);

setVisible(vero);

public static void main (Argomenti stringa) (

MoneyForNothing mfn = new MoneyForNothing();

Ed ecco lo stesso codice nella finestra di modifica FAR:

A proposito, ti consigliamo di digitare immediatamente i codici sorgente dei programmi nella codifica CP1251 (o nel linguaggio comune, nella codifica Windows): il cambio di codifica avviene premendo il tasto F8 e la codifica corrente viene visualizzata nella barra di stato in alto l'area di modifica.

Il punto di ingresso è rimasto invariato, ma il resto del codice è cambiato parecchio (ma non anticipiamoci). Una volta compilato ed eseguito dovresti vedere quanto segue:


Complimenti, in poche righe hai creato una vera finestra grafica! Può essere trascinato, ridimensionato, compresso, espanso e chiuso. È vero, la nostra finestra si è rivelata un po 'sbiadita, per dirla senza mezzi termini: "spaventosa". Inoltre, la finestra viene visualizzata nell'angolo in alto a sinistra dello schermo, ma la vorrei al centro: è più comoda da usare lì e questo output sembra più carino. Quindi facciamo un po' di lucidatura.

Innanzitutto, risolviamo il secondo problema: centrare la finestra. Qui ti consigliamo di fermarti e pensare: come lo faresti?

Diciamo che nella libreria grafica Java esiste un metodo setLocation, al quale vengono passate come parametri le coordinate dell'angolo in alto a sinistra della finestra (è da questo angolo che vengono posizionati gli altri elementi grafici all'interno della finestra). Ma se imposti questi parametri "frontalmente", quasi sicuramente non ne verrà fuori nulla di buono. su un altro monitor con una risoluzione diversa la finestra sarà completamente diversa da come ti aspettavi. Pertanto, le coordinate devono essere impostate in modo più intelligente.

Tutto ciò che serve per posizionare la finestra al centro è conoscere le dimensioni della finestra stessa (a proposito, sono impostate nel designer e formano un rettangolo di 600 per 400 pixel) e la risoluzione dello schermo, quindi, utilizzando aritmetica semplice, calcola le coordinate necessarie dell'angolo in alto a sinistra. Ciò si ottiene inserendo il seguente codice

Dimensione sSize = Toolkit.getDefaultToolkit().getScreenSize(),

fDimensione = getDimensione();

if (fSize.height > sSize.height) (fSize.height = sSize.height;)

if (fSize.width > sSize.width) (fSize.width = sSize.width;)

setLocation((sSize.larghezza - fSize.width)/2,

(dimensione s.altezza - dimensione f.altezza)/2);

immediatamente dopo la riga setSize(new Dimension(600, 400)); nel costruttore. Apportare le modifiche necessarie al codice sorgente, compilare il programma ed eseguirlo; la finestra dovrebbe apparire al centro dello schermo del monitor.

Ora qualche parola sull'aspetto della finestra. Il suo strano aspetto è spiegato dal fatto che gli sviluppatori Java hanno cercato di garantire che, indipendentemente dalla piattaforma hardware e dal "riempimento" del software, tutti gli elementi grafici (finestre, pulsanti, elenchi, ecc.) avessero un unico rendering e un'unica combinazione di colori. Per questo hanno sviluppato uno stile speciale, che hanno chiamato “METAL”. Se lo sviluppatore non fa sforzi particolari, gli elementi dell'interfaccia grafica nei suoi programmi appariranno esattamente in questo stile, senza tener conto delle caratteristiche di computer specifici e del loro software. In alcuni casi, questo ha senso, ma sarai comunque d'accordo che è molto meglio se un programma avviato su Windows è simile a un programma Windows e uno avviato su LINUX è simile a un programma Linux. Questo è facile da ottenere. Tutto quello che devi fare è includere il seguente codice nel punto di ingresso prima di istanziare la classe:

prova (UIManager.setLookAndFeel

(UIManager.getSystemLookAndFeelClassName());

catch (Eccezione lfe) ()

Questo è quello che faremo. Ora, dopo aver compilato la versione aggiornata del nostro programma ed averlo avviato per l'esecuzione, la finestra grafica apparirà molto più “decente”:


A seconda dell'impostazione delle proprietà dello schermo del monitor, la visualizzazione della finestra varierà; Usiamo il classico tema di Windows XP. Ad esempio, la stessa finestra potrebbe assomigliare a questa:

Verifica che tutto funzioni come previsto: la finestra appare al centro dello schermo e si presenta come previsto.

Con questo si conclude la nostra prima lezione sulle interfacce grafiche. In esso abbiamo mostrato la “facciata”, ma abbiamo tralasciato completamente molte questioni estremamente importanti e senza le quali la programmazione in Java in generale e nelle interfacce grafiche in particolare è impossibile. Inizieremo ad affrontare questi problemi nella prossima lezione, ma per ora giocate con il codice sorgente che avete.

Come esercizio, calcola, ad esempio, le coordinate di uscita della nostra finestra nell'angolo in basso a destra dello schermo e controlla il risultato.

Un altro esercizio è più semplice da eseguire, ma dovrai utilizzare la documentazione (prima o poi dovrai davvero iniziare): fai in modo che sia impossibile ridimensionare la finestra, ad es. in modo che l'area dei pulsanti di sistema sia come nell'immagine

(suggerimento: cerca parole chiave javax e JFrame). Quindi rimboccatevi le maniche e buona fortuna!

Commento

Può accadere che la finestra generata sia completamente o parzialmente invisibile (a causa del fatto che hai calcolato erroneamente le coordinate della sua visualizzazione sullo schermo). Anche i pulsanti di controllo della finestra potrebbero non essere più disponibili. Come puoi interrompere l'applicazione senza eliminare l'attività nel Task Manager o riavviare il computer?

Poiché lanciamo programmi per l'esecuzione da FAR, l'interruzione dell'esecuzione di un programma Java si ottiene premendo la combinazione di tasti Control-C (qui “C” è una lettera latina, non confonderla con una lettera cirillica simile).

Java ha 2 pacchetti principali per la creazione di interfacce utente grafiche. Questi sono Abstract Windows Toolkit (AWT) e Swing. AWT utilizza i widget del sistema operativo, quindi questa libreria è leggermente più veloce. Ma secondo me Swing è più ben progettato.

In questo tutorial esamineremo gli elementi di base della libreria Swing e creeremo una semplice interfaccia (GUI) come esempio.

I contenitori vengono utilizzati per raggruppare i componenti dell'interfaccia. Per creare il contenitore principale di un'applicazione, viene spesso utilizzato il contenitore JFrame (esistono anche JWindows e JApplet). Il modo più semplice è ereditare da JFrame e quindi accedere a molti metodi, ad esempio:

setBounds(x, y, w, h) - specifica le coordinate del vertice in alto a sinistra della finestra, nonché la sua larghezza e altezza.

setResizable(bool) - indica se la finestra può essere ridimensionata.

setTitle(str) - imposta il titolo della finestra.

setVisible(bool) - visualizza effettivamente la finestra.

setDefaultCloseOperation(operazione) - specifica l'operazione che verrà eseguita quando la finestra viene chiusa.

Controlli principali:

  • JLabel - elemento per la visualizzazione di testo fisso;
  • JTextField: semplice casella di modifica;
  • JButton - pulsante normale (pulsante);
  • JCheckBox - elemento di selezione (analogo al checkbox);
  • JRadioButton: pulsante di opzione

Come puoi vedere, tutto è abbastanza semplice e logico.

Quando si visualizzano i controlli, vengono utilizzati gestori speciali: LayoutManager. Tutti i LayoutManager dispongono di metodi per aggiungere e rimuovere elementi.

FlowLayout: utilizzato per visualizzare gli elementi in sequenza. Se un elemento non rientra in una determinata riga, apparirà in quella successiva.

GridLayout: visualizza gli elementi sotto forma di tabella con le stesse dimensioni di cella.

BorderLayout: utilizzato quando vengono visualizzati non più di 5 elementi. Questi elementi si trovano lungo i bordi della cornice e al centro: Nord, Sud, Est, Ovest, Centro.

BoxLayout: visualizza gli elementi in una riga o colonna.

GridBagLayout: consente di assegnare la posizione e la dimensione di ciascun widget. Questo è il tipo di visualizzazione più complesso, ma anche più efficace.

Vale anche la pena prestare attenzione alla gestione degli eventi. A questo scopo vengono utilizzati i cosiddetti Event Listener.

Bene, basta teoria, passiamo all'esempio della GUI:

Importa java.awt.*; importa java.awt.event.*; importa javax.swing.*; la classe pubblica SimpleGUI estende JFrame (pulsante JButton privato = nuovo JButton("Press"); input JTextField privato = nuovo JTextField("", 5); etichetta JLabel privata = nuovo JLabel("Input:"); JRadioButton privato radio1 = nuovo JRadioButton ("Seleziona questo"); private JRadioButton radio2 = new JRadioButton("Seleziona quello"); private JCheckBox check = new JCheckBox("Check", false); public SimpleGUI() ( super("Esempio semplice"); this.setBounds (100,100,250,100); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Contenitore contenitore = this.getContentPane(); contenitore.setLayout(new GridLayout(3,2,2,2)); contenitore.add(label); contenitore.add( input); ButtonGroup group = new ButtonGroup(); group.add(radio1); group.add(radio2); container.add(radio1); radio1.setSelected(true); container.add(radio2); container.add( check); button.addActionListener(new ButtonEventListener()); container.add(button); ) la classe ButtonEventListener implementa ActionListener ( public void actionPerformed(ActionEvent e) ( String message = ""; messaggio += "Il pulsante è stato premuto\n"; messaggio += "Il testo è " + input.getText() + "\n"; messaggio += (radio1.isSelected()?"Radio #1":"Radio #2") + " è selezionato\n"; messaggio += "CheckBox è " + ((check.isSelected()) ?"checked":"deselezionato"); JOptionPane.showMessageDialog(null, messaggio, "Output", JOptionPane.PLAIN_MESSAGE); ) ) public static void main(String args) ( SimpleGUI app = new SimpleGUI(); app.setVisible(true); ) )

Appunti:

getContentPane restituisce il contenitore di livello superiore. ButtonGroup viene utilizzato per creare un gruppo di pulsanti di opzione interconnessi.

La classe interna ButtonActionListener implementa l'interfaccia ActionListener. Per fare ciò, è necessario fornire un'implementazione del metodo actionPerformed.

JOptionPane viene utilizzato per visualizzare le finestre di dialogo.

Aspetto con ansia le vostre domande e commenti. Se vuoi saperne di più su Swing, fammelo sapere e presto scriverò un altro articolo con tecniche e componenti più avanzati.

In questo breve articolo voglio descrivere il processo di creazione di un piccolo programma che supporti la GUI nel linguaggio Giava. Si presuppone che il lettore abbia familiarità con le basi della lingua Giava.

Quindi, di quali strumenti abbiamo bisogno:

  • Macchina virtuale Java (OpenJDK o Oracle JDK)
  • Intellij IDEA (o altro IDE Java)

Dopo aver installato il software necessario, apri IDEA intelligente e creare un nuovo progetto: File -> Nuovo progetto…

Ho dato un nome al progetto guiBase. Come puoi vedere nello screenshot, la cartella src non contiene nulla, quindi creiamo al suo interno la nostra classe principale contenente la funzione principale.

Classe pubblica Main ( public static void main(String args) ( System.out.println("Ciao, Govzalla!"); ) )

Puoi vedere il contenuto della classe principale sopra. Ora possiamo creare un progetto ( Costruisci progetto ) ed eseguirlo ( Correre ). Giù nel tuo terminale IDE vedrai un messaggio "Ciao, Govzalla!". Ma come hai capito tu stesso, non supporta la GUI.

In questa fase abbiamo già un programma funzionante, ma senza supporto GUI. E ora nella stessa cartella src creiamo Modulo GUI: Nuovo -> Modulo GUI

Aprire il modulo GUI creato, fare clic su JPanel e impostare il suo identificatore nel campo nome del campo, Ho chiesto pannello.

Quindi trascinalo sul modulo sul lato destro JTextField, JPasswordField E JPulsante:

Non resta che aggiungere il codice e collegare ad esso il nostro modulo. Quando abbiamo aggiunto il form Finestra principale, la classe è stata creata automaticamente Finestra principale, questa classe è la classe del modulo creato, cioè È questa classe che servirà tutti gli eventi di questo modulo.

Sebbene la nostra classe finestra contenga gli elementi necessari, anche adesso non ha nulla a che fare con la GUI, quindi estendiamola con JFrame ed ereditare tutte le funzionalità GUI di base e necessarie .

Attualmente abbiamo il modulo Finestra principale e classe Finestra principale esteso con JFrame. Ora dobbiamo definire tutti gli elementi GUI aggiunti come contenuto della classe Finestra principale this.getContentPane().add(pannello); Dopodiché il contenuto del file MainWindow.java verrà modificato come segue:

Importa javax.swing.*; la classe pubblica MainWindow estende JFrame ( private JTextField textField1; private JPasswordField passwordField1; private JButton button1; pannello privato JPanel; public MainWindow() ( this.getContentPane().add(panel); ) )

Se provi a eseguire il codice, vedrai di nuovo lo stesso messaggio "Hello, Govzalla!". Il fatto è che abbiamo creato una classe e un modulo per essa, ma non abbiamo creato un'istanza di questa classe.

È ora di modificare il file Main.java e aggiungere lì il codice per creare la nostra GUI:

Importa java.awt.*; public class Main ( public static void main(String args) ( // Crea un'istanza della classe MainWindow MainWindow mainWindow = new MainWindow(); // Comprimi tutti gli elementi dal nostro modulo mainWindow.pack(); // Ridimensiona la finestra mainWindow.setSize( new Dimension(200, 200)); // Visualizza la finestra creata mainWindow.setVisible(true); ) )

Esecuzione del codice

Facendo clic sul pulsante Pulsante, noterai che il programma non risponde affatto. Il fatto è che non abbiamo ancora aggiunto un ascoltatore ( Ascoltatore) per eventi ( Eventi) pulsante Pulsante.

Ascoltatore di eventi ( Ascoltatore di eventi) JPulsante deve essere un adattatore per l'impianto ActionListener, quindi aggiungiamo il seguente codice al corpo della classe Finestra principale:

La classe privata MyButtonListener implementa ActionListener ( @Override public void actionPerformed(ActionEvent actionEvent) ( ) )

Metodo azione eseguita() elaborerà tutti gli eventi di button1, ma prima devi ancora dire a button1 quale classe elaborerà, quindi aggiungi il seguente codice al costruttore della classe MainWIndow: this.button1.addActionListener(new MyButtonListener()); Per evitare che il nostro gestore sia privo di significato, aggiungi il seguente codice al metodo azione eseguita():

@Override public void actionPerformed(ActionEvent actionEvent) ( if (textField1.getText().equals(passwordField1.getText())) ( JOptionPane.showMessageDialog(null, "Successo"); ) else ( JOptionPane.showMessageDialog(null, "Errore " "); ) )

Ora il programma reagirà correttamente agli eventi, ma ovviamente non a tutti gli eventi. Ad esempio, se provi a disabilitare il programma cliccando sulla croce, la finestra scomparirà, ma il programma continuerà a funzionare, perché Il gestore eventi della finestra principale non è stato aggiunto.

L'interfaccia utente in Java ha attraversato un percorso di formazione e sviluppo molto spinoso. Per molto tempo è stato accusato di lentezza nel lavoro, avidità di risorse di sistema e funzionalità limitata. L'avvento di .NET con componenti grafici più veloci ha ulteriormente minato la posizione di Java. Ma ogni nuvola ha un lato positivo: tutto questo movimento ha solo spinto gli sviluppatori Java a sviluppare e migliorare le librerie grafiche. Vediamo cosa ne viene fuori.

Kit di strumenti per finestre astratte

AWT è stato il primo tentativo di Sun di creare una GUI per Java. Hanno preso la strada più semplice e hanno semplicemente creato un livello Java che richiama i metodi dalle librerie scritte in C. I metodi della libreria creano e utilizzano componenti grafici dell'ambiente operativo. Da un lato questo è positivo, poiché un programma Java è simile ad altri programmi all'interno di questo sistema operativo. D'altra parte, non vi è alcuna garanzia che le differenze nelle dimensioni dei componenti e nei caratteri non rovinino l'aspetto del programma quando viene eseguito su un'altra piattaforma. Inoltre, per garantire la funzionalità multipiattaforma, è stato necessario unificare le interfacce di chiamata dei componenti, motivo per cui la loro funzionalità è stata leggermente ridotta. E il set di componenti si è rivelato piuttosto piccolo. Ad esempio, AWT non dispone di tabelle e i pulsanti non supportano la visualizzazione delle icone.

AWT tenta di rilasciare automaticamente le risorse utilizzate. Ciò aggiunge un po' di complessità all'architettura e influisce sulle prestazioni. AWT è abbastanza facile da imparare, ma scrivere qualcosa di complesso sarà alquanto difficile. Al giorno d'oggi viene utilizzato solo per le applet.

Vantaggi:

  • Parte JDK;
  • velocità di lavoro;
  • i componenti grafici sono simili a quelli standard.

Screpolatura:

  • l'uso di componenti nativi impone restrizioni sull'uso delle loro proprietà. Alcuni componenti potrebbero non funzionare affatto su piattaforme non native;
  • alcune proprietà, come icone e tooltip, sono completamente assenti in AWT;
  • Esistono pochissimi componenti AWT standard; il programmatore deve implementarne molti personalizzati;
  • il programma appare diverso su piattaforme diverse (potrebbe essere storto).

conclusione:

Attualmente AWT viene utilizzato molto raramente, principalmente in vecchi progetti e applet. Oracle ha tutorial nascosti e incoraggia la transizione a Swing in ogni modo possibile. Ciò è comprensibile; l’accesso diretto ai componenti dell’asse può diventare una grave falla di sicurezza.

Oscillazione


Dopo AWT, Sun ha sviluppato una serie di componenti grafici chiamati Swing. I componenti Swing sono scritti interamente in Java. Il 2D viene utilizzato per il rendering, il che porta con sé numerosi vantaggi. Il set di componenti standard supera significativamente AWT in varietà e funzionalità. È diventato facile creare nuovi componenti, ereditando da quelli esistenti e disegnando tutto ciò che il tuo cuore desidera. È diventato possibile il supporto per vari stili e skin. Tuttavia, la velocità delle prime versioni di Swing lasciava molto a desiderare. Un programma scritto in modo errato potrebbe bloccare completamente Windows.

Tuttavia, grazie alla sua facilità d'uso, alla ricca documentazione e ai componenti flessibili, Swing è diventato forse il framework grafico più popolare in Java. Sulla base di esso sono apparse molte estensioni, come SwingX, JGoodies, che semplificano notevolmente la creazione di interfacce utente complesse. Quasi tutti gli ambienti di programmazione Java più diffusi includono editor grafici per i moduli Swing. Pertanto, comprendere ed iniziare ad utilizzare Swing non sarà difficile.

Vantaggi:

  • parte del JDK, non è necessario installare librerie aggiuntive;
  • ci sono molti altri libri sullo Swing e risposte sui forum. Tutti i problemi, soprattutto per i principianti, sono perfettamente noti a Google;
  • editor di moduli integrato in quasi tutti gli ambienti di sviluppo;
  • ci sono molte estensioni basate sullo swing come SwingX;
  • supporto per diversi stili (aspetto grafico).

Screpolatura:

  • una finestra con molti componenti inizia a rallentare;
  • Lavorare con i gestori di layout può essere un incubo in interfacce complesse.

Conclusione:

Swing ha vissuto, Swing è vivo, Swing vivrà. Sebbene Oracle stia cercando di promuovere JavaFX, Swing rimane oggi il framework più popolare per la creazione di interfacce utente in Java.

Kit di strumenti widget standard


Come
sembra
S.W.T.

SWT è stato sviluppato da IBM in un periodo in cui Swing era ancora lento, ed è stato realizzato principalmente per promuovere l'ambiente di programmazione Eclipse. SWT, come AWT, utilizza componenti del sistema operativo, ma ha le proprie interfacce di interazione per ciascuna piattaforma. Quindi per ogni nuovo sistema dovrai fornire una libreria JAR separata con la versione appropriata di SWT. Ciò ha permesso di utilizzare in modo più completo la funzionalità esistente dei componenti su ciascun asse. Le funzionalità e i componenti mancanti sono stati implementati utilizzando il 2D come in Swing. SWT ha molti aderenti, ma, in tutta sincerità, non si può fare a meno di concordare sul fatto che tutto si è rivelato non così semplice come vorremmo. Un principiante dovrà dedicare molto più tempo all'apprendimento dell'SWT che alla familiarità con lo Swing. Inoltre, SWT affida al programmatore il compito di liberare risorse e quindi deve prestare particolare attenzione durante la scrittura del codice, in modo che un'eccezione accidentale non porti a perdite di memoria.

Vantaggi:

  • utilizza componenti del sistema operativo: velocità maggiore;
  • Eclipse fornisce un editor di moduli visivi;
  • ampia documentazione e molti esempi;
  • È possibile utilizzare i componenti AWT e Swing.

Screpolatura:

  • dovrà essere fornita una libreria separata per ciascuna piattaforma;
  • è necessario monitorare costantemente l'utilizzo delle risorse e rilasciarle tempestivamente;
  • architettura complessa che evoca pensieri suicidi dopo inutili tentativi di implementare un'interfaccia personalizzata.

Conclusione:

È chiaro che IBM ci ha provato. Ma si è rivelato un lavoro molto amatoriale...

JavaFX


JavaFX può essere definito una svolta senza esagerare. La pipeline grafica viene utilizzata per il rendering, il che velocizza notevolmente l'applicazione. Il set di componenti integrati è ampio, ci sono anche componenti separati per disegnare grafici. È implementato il supporto per contenuti multimediali, molti effetti di visualizzazione, animazioni e persino multi-touch. L'aspetto di tutti i componenti può essere facilmente modificato utilizzando gli stili CSS. E la cosa migliore è che JavaFX include una serie di utilità che ti permettono di creare un programma di installazione nativo per le piattaforme più popolari: exe o msi per Windows, deb o rpm per Linux, dmg per Mac. Puoi trovare documentazione dettagliata e un numero enorme di esempi già pronti sul sito Web di Oracle. Ciò rende la programmazione con JavaFX facile e divertente.

Vantaggi:

  • lavoro veloce grazie alla pipeline grafica;
  • molti componenti diversi;
  • supporto allo stile;
  • utilità per la creazione di un programma di installazione;
  • L'applicazione può essere avviata come applicazione desktop e in un browser come parte di una pagina.

Screpolatura:

  • il framework è ancora in fase di sviluppo, quindi si verificano arresti anomali e alcuni problemi tecnici;
  • JavaFX non è ancora ampiamente utilizzato.

Conclusione:

Ottimo lavoro, Oracolo. Il quadro lascia solo impressioni positive. Non è difficile da capire; i metodi e le interfacce sembrano logici. Voglio usarlo ancora e ancora!

Biblioteche visive in pratica

SWT: widget meteo

Per dimostrare le capacità delle librerie grafiche più popolari e i principi di base per lavorare con esse, creeremo diversi piccoli widget che visualizzano varie informazioni.

E cominciamo con, forse, il widget più popolare: la visualizzazione del tempo attuale, per la cui implementazione sceglieremo SWT.

Qualsiasi programma SWT inizia creando un oggetto Display. Funziona come una sorta di contesto applicativo che contiene i metodi necessari per accedere alle risorse di sistema e fornisce un ciclo di eventi. Il passo successivo è creare l'oggetto altrettanto importante Shell. Shell è una normale finestra del sistema operativo. Display viene passato al costruttore della shell per creare la finestra di livello superiore.

Visualizza display = nuovo Display(); shell = nuova Shell(display, SWT.NO_TRIM);

Poiché stiamo creando un widget, non abbiamo bisogno di visualizzare la cornice della finestra e i pulsanti di controllo standard, per questo abbiamo specificato il flag NO_TRIM. Per lo sfondo utilizzeremo un'immagine: un rettangolo con angoli arrotondati. In linea di principio, una finestra SWT può assumere qualsiasi forma. Per ottenere questo effetto, utilizziamo la classe Region. Tutto quello che devi fare è aggiungere tutti i punti visibili dall'immagine di sfondo a questa classe, saltando quelli trasparenti.

Caricamento di un'immagine:

Immagine immagine = nuova immagine(display, "images/bg.png#26759185");

Nelle immagini di formati diversi, la trasparenza è impostata in modo diverso e pertanto anche le informazioni sulle aree trasparenti non vengono recuperate nello stesso modo. Crea un'area di sfondo e aggiungi tutti i punti visibili lì:

Regione regione = nuova Regione(); ImageData imageData = image.getImageData(); if (imageData.alphaData != null) ( Pixel rettangolo = nuovo Rettangolo(0, 0, 1, 1); for (int y = 0; y< imageData.height; y++) { for (int x = 0; x < imageData.width; x++) { if (imageData.getAlpha(x, y) == 255) { pixel.x = imageData.x + x; pixel.y = imageData.y + y; region.add(pixel); } } } } else { ImageData mask = imageData.getTransparencyMask(); Rectangle pixel = new Rectangle(0, 0, 1, 1); for (int y = 0; y < mask.height; y++) { for (int x = 0; x < mask.width; x++) { if (mask.getPixel(x, y) != 0) { pixel.x = imageData.x + x; pixel.y = imageData.y + y; region.add(pixel); } } } }

Imposta la forma della finestra:

Shell.setRegion(regione);

Ora dobbiamo creare un ascoltatore di eventi per la finestra. Saremo interessati agli eventi di disegno della finestra, agli eventi del mouse e agli eventi di pressione dei tasti in modo che la finestra possa essere spostata sullo schermo.

Listener listener = new Listener() ( int startX, startY; public void handleEvent(Event e) ( if (e.type == SWT.KeyDown && e.character == SWT.ESC) ( shell.dispose(); ) if (e.type == SWT.MouseDown && e.button == 1) ( startX = e.x; startY = e.y; ) if (e.type == SWT.MouseMove && (e.stateMask & SWT.BUTTON1) != 0 ) ( Point p = shell.toDisplay(e.x, e.y); p.x -= startX; p.y -= startY; shell.setLocation(p); ) if (e.type == SWT.Paint) ( e.gc.drawImage( immagine, imageData.x, imageData.y); ) ) );

Quindi, premendo il tasto Esc si chiuderà la finestra. Quando premi il tasto sinistro del mouse su un'area della finestra, ricorda le coordinate del clic. Quando si sposta il mouse tenendo premuto il tasto sinistro, spostiamo la finestra sullo schermo in base al movimento. Quando si verifica un evento di ridisegno, disegniamo un'immagine di sfondo utilizzando il contesto grafico GC.

Assegniamo un ascoltatore agli eventi della finestra corrispondente:

Shell.addListener(SWT.KeyDown, ascoltatore); shell.addListener(SWT.MouseDown, ascoltatore); shell.addListener(SWT.MouseMove, ascoltatore); shell.addListener(SWT.Paint, ascoltatore);

Imposta la dimensione della finestra uguale alla dimensione dell'immagine:

Shell.setSize(imageData.x + imageData.width, imageData.y + imageData.height);

Apri una finestra e avvia il ciclo degli eventi:

Shell.open(); while (!shell.isDisposed ()) ( if (!display.readAndDispatch ()) display.sleep (); )

Non dimenticare di rilasciare le risorse utilizzate alla fine:

Regione.dispose(); immagine.dispose(); display.dispose();

Eseguendo il programma in questa fase otterremo un rettangolo che potrà essere spostato con il mouse e chiuso con Esc.

È ora di aggiungere alcuni contenuti. Mostreremo il meteo attuale sotto forma di icona di stato (soleggiato, pioggia, neve...), letture della temperatura e ora dell'ultimo aggiornamento.

I gestori del layout vengono utilizzati per disporre i componenti grafici nella finestra nella forma desiderata. Il gestore del layout si occupa non solo del posizionamento dei componenti, ma anche del loro ridimensionamento al variare delle dimensioni della finestra. Per il nostro widget utilizzeremo GridLayout. Questo gestore posiziona i componenti nelle celle di una tabella immaginaria. Creiamo un GridBagLayout con due colonne con larghezze diverse (false flag nel costruttore), lo impostiamo come gestore del layout della finestra:

Layout GridLayout = nuovo GridLayout(2, false); shell.setLayout(disposizione);

Per l'immagine di stato utilizziamo il componente Label. Passiamo l'oggetto finestra come genitore. Il secondo parametro può essere utilizzato per impostare lo stile del componente. Per ogni componente, l’insieme dei possibili flag di stile è diverso; possono essere trovati nella documentazione o direttamente nel codice sorgente del componente.

//disegna l'immagine di stato Label imageLabel = new Label(shell, SWT.NONE); imageLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, true, 1, 1));

I flag nella classe GridData indicano che l'etichetta sarà posizionata in alto a sinistra, si estenderà orizzontalmente e verticalmente (flag impostati su true) quando c'è spazio libero e occuperà una riga e una colonna della tabella di layout.

In SWT non c'è uno sfondo trasparente dei componenti e dietro l'immagine di stato ci sarà uno sfondo bianco, il che, ovviamente, non sarebbe auspicabile. Creiamo quindi un oggetto Color con il colore di sfondo della finestra:

Colore bgColor = nuovo Colore(display, 0x2b, 0x2b, 0x2b);

Alla fine del programma anche questo oggetto dovrà essere eliminato richiamando il metodo Dispose. Impostiamo il colore di sfondo e l'immagine di stato, che possono essere caricati dal file nello stesso modo in cui abbiamo caricato l'immagine di sfondo all'inizio:

ImageLabel.setBackground(bgColor); Stato dell'immagineImmagine = nuova immagine(display, "images/1.png#26759185"); imageLabel.setImage(statusImage);

Ora aggiungiamo un'etichetta con la temperatura attuale e posizioniamola nella parte in alto a destra della finestra:

Etichetta temperaturaLabel = nuova etichetta(shell, SWT.NONE); temperatureLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false, 1, 1));

Impostiamo una certa temperatura:

TemperatureLabel.setText("+1 \u2103");

Per registrare la temperatura in gradi Celsius viene utilizzato il numero Unicode del carattere corrispondente con i caratteri di servizio \u.

Il carattere predefinito per le etichette di testo è troppo piccolo. Quindi creiamone uno nuovo, più grande:

FontData fD = temperatureLabel.getFont().getFontData(); fD.setHeight(30); fD.setStyle(SWT.BOLD); Carattere nuovoFont = nuovo Carattere(display, fD); etichettatemperatura.setFont(nuovoFont); Il carattere, come altri oggetti risorsa, deve essere liberato. Per fare ciò, utilizzeremo un ascoltatore di eventi di distruzione dell'etichetta:

TemperatureLabel.addDisposeListener(new DisposeListener() ( public void widgetDisposed(DisposeEvent e) ( newFont.dispose(); ) ));

Infine, aggiungiamo un'etichetta che descrive le condizioni meteorologiche:

Descrizione etichettaLabel = nuova etichetta(shell, SWT.WRAP); descriptionLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true, 2, 1)); descriptionLabel.setText("Parzialmente nuvoloso, leggera pioggia"); descrizioneLabel.setBackground(bgColor); descrizioneLabel.setForeground(display.getSystemColor(SWT.COLOR_WHITE));

Il testo può essere piuttosto lungo, quindi quando creiamo un'etichetta specifichiamo il flag WRAP in modo che il testo venga automaticamente suddiviso in più righe se non c'è abbastanza spazio. Posizioniamo il componente al centro e lasciamo che riempia l'intero spazio orizzontale. Segnaliamo inoltre che il componente occupa due colonne della tabella di layout. Lanciamo e otteniamo la finestra dall'immagine "Weather Widget".

Ora puoi allegare un servizio meteo, creare un timer per l'aggiornamento automatico e il widget è pronto.

Swing: sempre le ultime novità

Scriveremo un widget in Swing per visualizzare i feed RSS. Iniziamo, come l'ultima volta, creando una finestra. La classe che implementa la funzionalità di una finestra standard in Swing si chiama JFrame. Per impostazione predefinita, la chiusura di una finestra dell'applicazione in Swing non provoca l'arresto del programma, quindi è meglio specificare come dovrebbe comportarsi la finestra una volta chiusa:

Cornice JFrame = nuova JFrame(); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

Un tavolo è l'ideale per presentare le notizie. Swing è basato sul modello Model-View-Controller (MVC). Nell'architettura MVC, il modello fornisce i dati, la vista è responsabile della visualizzazione dei dati (ad esempio testo, campi di input) e il controller fornisce l'interazione tra il modello e la vista. La tabella illustra bene questo approccio. Per rappresentare i dati, viene utilizzata una classe che implementa l'interfaccia TableModel.

Per memorizzare informazioni sulle notizie disponibili, creiamo una classe FeedMessage con campi per il titolo dell'articolo e la data di pubblicazione:

Classe pubblica FeedMessage (public String titolo; public DatepublicationDate;)

Per semplificare e accelerare lo sviluppo, ereditiamo il nostro modello di dati dalla classe AbstractTableModel, che offre un'implementazione già pronta di quasi tutti i metodi dell'interfaccia TableModel.

La classe pubblica RssFeedTableModel estende AbstractTableModel (list voci = nuovo ArrayList<>(); public void updateData(List voci) ( this.entries = voci; fireTableDataChanged(); ) public int getRowCount() ( return entry.size(); ) public int getColumnCount() ( return 2; ) public Object getValueAt(int rowIndex, int columnIndex) ( switch (columnIndex) ( caso 0: restituisce voci.get(rowIndex).title; caso 1: restituisce voci.get(rowIndex).publicationDate; ) restituisce null; ) )

Il metodo fireTableDataChanged indica alla vista che il modello dati è cambiato e deve essere ridisegnato.

Creiamo una tabella e ne modifichiamo leggermente l'aspetto in modo che assomigli più a un widget. Rimuoviamo le linee tra righe e colonne, aumentiamo l'altezza della riga e rimuoviamo l'intestazione della tabella con i nomi delle colonne:

Tabella JTable = nuova JTable(new RssFeedTableModel()); table.setShowGrid(falso); table.setIntercellSpacing(nuova dimensione(0, 0)); table.setRowHeight(30); table.setTableHeader(null);

Ora diamo un'occhiata all'aspetto delle cellule. Swing consente di assegnare classi di visualizzazione separate per diversi tipi di dati. Una classe che eredita l'interfaccia TableCellRenderer è responsabile del rendering delle singole celle della tabella. L'impostazione predefinita è DefaultTableCellRenderer, che è un'etichetta di testo.

Assegniamo il nostro renderer di celle a dati di tipo String. Cambiamo il colore predefinito del carattere e facciamo in modo che il colore dello sfondo si alterni per migliorare la leggibilità.

Table.setDefaultRenderer(String.class, new DefaultTableCellRenderer() ( Color oddColor = new Color(0x25, 0x25, 0x25); Color evenColor = new Color(0x1a, 0x1a, 0x1a); Color titleColor = new Color(0x3a, 0xa2, 0xd7 ); componente pubblico getTableCellRendererComponent(tabella JTable, valore oggetto, booleano isSelected, booleano hasFocus, int riga, int colonna) ( super.getTableCellRendererComponent(tabella, valore, isSelected, hasFocus, riga, colonna); setBackground(riga % 2 == 0 ? oddColor: evenColor); setForeground(titleColor); setFont(font); restituisce questo; ) ));

Affinché la tabella inizi a utilizzare il nostro renderer, dobbiamo aggiungere un metodo che restituisca il tipo di dati per ciascuna cella al modello dati:

Classe pubblicagetColumnClass(int columnIndex) ( switch (columnIndex) ( caso 0: restituisce String.class; caso 1: restituisce Date.class; ) restituisce Object.class; )

Le novità possono essere tante, quindi posizioniamo la tabella sulla barra di scorrimento e rendiamo invisibile lo slider di scorrimento in modo che non rovini il design del widget:

JScrollPane scrollPane = nuovo JScrollPane(tabella); table.setFillsViewportHeight(true); scrollPane.getVerticalScrollBar().setPreferredSize(nuova dimensione(0,0));

Aggiungi un componente di scorrimento al pannello della finestra principale. Il secondo argomento può essere il posizionamento del componente. Per impostazione predefinita, il pannello della finestra principale utilizza il gestore di layout BorderLayout, che dispone i componenti in base alle direzioni cardinali. Posizioniamo una tabella con lo scorrimento al centro.

Frame.getContentPane().add(scrollPane, BorderLayout.CENTER);

Come l'ultima volta, rimuoveremo il telaio della finestra standard. E come titolo della finestra utilizzeremo un'etichetta di testo stilizzata, che posizioneremo nella parte superiore della finestra.

Titolo JLabelLabel = nuova JLabel("Xakep RSS"); Titolo del carattereFont = new Font("Arial", Font.BOLD, 20); titoloLabel.setFont(titoloFont); titoloLabel.setHorizontalAlignment(SwingConstants.CENTER); titoloLabel.setForeground(Color.WHITE); titleLabel.setPreferredSize(nuova dimensione(0, 40)); frame.getContentPane().add(titleLabel, BorderLayout.NORTH);

A differenza di SWT, gli oggetti colore e carattere vengono liberati automaticamente, quindi non devi più preoccuparti di perdite di memoria.

Aggiungi ascoltatori del mouse in modo che la finestra possa essere spostata sullo schermo.

Listener MouseAdapter = new MouseAdapter() ( int startX; int startY; public void mousePressed(MouseEvent e) ( if (e.getButton() == MouseEvent.BUTTON1) ( startX = e.getX(); startY = e.getY( ); ) ) public void mouseDragged(MouseEvent e) ( Point currCoords = e.getLocationOnScreen(); frame.setLocation(currCoords.x - startX, currCoords.y - startY); ) ); titleLabel.addMouseListener(ascoltatore); titleLabel.addMouseMotionListener(ascoltatore);

Ora cambiamo la forma della finestra in un rettangolo con angoli arrotondati. È meglio farlo in un ascoltatore di componenti, poiché se la dimensione della finestra cambia, la forma della finestra verrà ricalcolata correttamente:

Frame.addComponentListener(new ComponentAdapter() ( public void componenteResized(ComponentEvent e) ( frame.setShape(new RoundRectangle2D.Double(0, 0, frame.getWidth(), frame.getHeight(), 20, 20)); ) ) );

Imposta la dimensione della finestra, rimuovi la cornice e rendi la finestra traslucida.

Frame.setSize(520, 300); frame.setUndecorated(true); frame.setOpacità(0.85f);

Infine, apriamo la finestra nel flusso grafico. SwingUtilities.invokeLater(new Runnable() ( public void run() ( frame.setVisible(true); ) ));

Non resta che aggiungere il caricamento dei dati in un thread separato e otterremo un widget come questo con le ultime notizie dalla tua rivista preferita :).


JavaFX: ascoltiamo un po' di musica

E infine, il momento clou della stagione è JavaFX. Usiamo le sue capacità multimediali e il suo componente per tracciare e creare un semplice equalizzatore.

Innanzitutto, ereditiamo la classe widget da Application. Questa è la classe dell'applicazione principale in JavaFX. L'applicazione contiene i principali metodi del ciclo di vita dell'applicazione. I componenti del modulo vengono creati nel metodo start, che accetta la classe Stage come argomento. Stage è una finestra di programma. Cambiamo lo stile della finestra in TRASPARENTE per rimuovere il bordo e i pulsanti. Lo Stage contiene la classe Scene, che imposta la dimensione della finestra e il colore dello sfondo. In Scene, a sua volta, passiamo alla classe Group, nella quale inseriremo i componenti figlio:

Public void start(Stage primarioStage) ( primarioStage.initStyle(StageStyle.TRANSPARENT); Radice del gruppo = nuovo Gruppo(); Scena scena = nuova Scena(radice, 400, 200, Color.TRANSPARENT); primarioStage.setScene(scena);

Per visualizzare l'equalizzatore, utilizziamo un grafico a barre, lungo gli assi del quale visualizzeremo la frequenza e la potenza sonora:

CategoryAxis xAxis = new CategoryAxis(); NumeroAsseyAsse = nuovo NumeroAsse(0,50,10); Grafico a barre bc = nuovo grafico a barre (Assex,Assey); bc.setPrefSize(400, 200); bc.setLegendVisible(falso); bc.setAnimated(falso); bc.setBarGap(0); bc.setCategoryGap(1); bc.setVerticalGridLinesVisible(false); bc.setHorizontalGridLinesVisible(false); xAxis.setLabel("Frequenza"); yAxis.setLabel("Potenza"); yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis, null, "dB"));

Compila il diagramma con i dati iniziali:

Serie.XYChart serie1 = nuova XYChart.Series (); serie1Data = nuovo XYChart.Data; Categorie di stringhe = nuova stringa; for (int i=0; i (categorie[i], 50); serie1.getData().add(serie1Data[i]); ) bc.getData().add(serie1);

Crea un rettangolo con angoli arrotondati per dare al widget la forma appropriata:

Rettangolo rettangolo = nuovo Rettangolo(0, 0, 400, 200); Stop stop = new Stop ( new Stop(0, new Color(0, 0, 0, 0.8)), null); LinearGradient lg2 = new LinearGradient(0, 0, 0, 0, false, CycleMethod.NO_CYCLE, si ferma); rettangolo.setFill(lg2); rettangolo.setArcHeight(20); rettangolo.setArcWidth(20);

Aggiungi entrambi i componenti al gruppo:

Root.getChildren().addAll(rettangolo, bc);

Assegnamo gli ascoltatori del mouse a un gruppo per spostare la finestra sullo schermo:

Root.setOnMousePressed(nuovo EventHandler () ( public void handle(MouseEvent me) ( initX = me.getScreenX() - primariaStage.getX(); initY = me.getScreenY() - primariaStage.getY(); ) )); root.setOnMouseDragged(nuovo EventHandler () ( public void handle(MouseEvent me) ( primarioStage.setX(me.getScreenX() - initX); primarioStage.setY(me.getScreenY() - initY); ) ));

Carica la canzone nel player:

File file = new File("portami fuori di qui.mp3"); Audio multimedialeMedia = null; audioMedia = new Media(file.toURI().toURL().toString()); audioMediaPlayer = nuovo MediaPlayer(audioMedia);

Aggiungi un ascoltatore che aggiornerà il grafico a barre:

AudioMediaPlayer.setAudioSpectrumListener(nuovo AudioSpectrumListener() ( public void spectrumDataUpdate(doppio timestamp, doppia durata, grandezze float, fasi float) ( for (int i = 0; i< series1Data.length; i++) { series1Data[i].setYValue(magnitudes[i] + 60); } } });

Rendi visibile la scena e avvia la canzone:

PrimaryStage.mostra(); audioMediaPlayer.play();

Avvia l'applicazione:

Public static void main(String args) ( launch(args); )

E godiamo di tanta bellezza.