Ciao, sto progettando un giochino per l'università e ovviamente ho a che fare con interfaccia grafica.
So che a ogni pannello posso applicare un determinato Layout che si differenzia dagli altri per come posizione poi gli oggetti.
Ho letto che per implementare un interfaccia un po' più complessa e gradevole è meglio dividere la propria idea in zone.. ed ad ogni zona associare un pannello con il layout più opportuno. Ora, una bozza della mia idea è questa:
http://img223.imageshack.us/img223/6822/bozzamz7.jpg
La mia idea era quella di dividere i pannelli in livelli.. cioè spiego meglio..
Un pannello di primo livello che conterrà i pannelli di secondo livello che a loro volta conterranno i pannelli di terzo livello.
Avevo pensato di usare un Border Layout per il primo livello in modo da poter inserire due pannelli di secondo livello a OVEST e a EST.. ma ho dei problemi.. perchè questi si schiacciano ai lati del primo pannello e non si vede niente.. si vedono solo se li metto come CENTER..
Prima domanda:
-C'è un modo per regolare (e quindi nel mio caso aumentare) lo spazio occupato da un pannello inserito per esempio a NORD di un pannello con Border Layout?
Se il mio approccio è completamente sbagliato o quasi, mi suggerite voi come affrontare la cosa per avere l'interfaccia come nell'immagine che ho postato?
Ho letto del Layout: GridBagLayout.. che divide la zona in righe e colonne di dimensioni variabili.. però so che è molto difficile da usare.. voi che mi dite?
Aiutatemi Gentilmente :rolleyes:
Secondo gli ingegneroni di Sun dovresti usare GridBagLayout o SpringLayout. Il primo è 'na specie di Sudoku. Il secondo è molto semplice se usi un solo componente. Con due componenti ti viene la sindrome del vaffanc##@.
Le alternative sono due. La prima è usare uno degli strumenti per la costruzione visuale di interfacce utente. Aggiungono quattro milioni di linee di codice per ogni etichetta inserita e poi lo blindano in modo tale che se cambi una virgola ti esplode il PC.
La seconda è creare un tuo LayoutManager che è facilissmo. Nel tuo caso hai quattro aree rettangolari. Le due a destra sono alte ognuna il 50% dell'altezza del contenitore e larghe complessivamente il 67% della larghezza del contenitore. La cella in alto a sinistra è larga il 33% e alta il 25%. Il componente lungo è largo il 33% e alto il 75. Te la cavi con due conti e qualche linea.
Secondo gli ingegneroni di Sun dovresti usare GridBagLayout o SpringLayout. Il primo è 'na specie di Sudoku. Il secondo è molto semplice se usi un solo componente. Con due componenti ti viene la sindrome del vaffanc##@.
Le alternative sono due. La prima è usare uno degli strumenti per la costruzione visuale di interfacce utente. Aggiungono quattro milioni di linee di codice per ogni etichetta inserita e poi lo blindano in modo tale che se cambi una virgola ti esplode il PC.
La seconda è creare un tuo LayoutManager che è facilissmo. Nel tuo caso hai quattro aree rettangolari. Le due a destra sono alte ognuna il 50% dell'altezza del contenitore e larghe complessivamente il 67% della larghezza del contenitore. La cella in alto a sinistra è larga il 33% e alta il 25%. Il componente lungo è largo il 33% e alto il 75. Te la cavi con due conti e qualche linea.
L'idea del LayoutManager personalizzato mi piace. Ma non ho proprio idea di come si faccia.. potresti darmi qualche dritta?
In ogni caso appena ho tempo mi spulcio un po' il codice delle classi layout di java..
E' facilissimo. Hai un Container in cui infili i componenti. I componenti sono disegnati in regioni dello spazio assegnate al Container secondo quanto stabilito nel LayoutManager. E qui abbiam già detto tutto.
Supponiamo di voler disegnare un componente nell'angolo in alto a sinistra del suo contenitore. Non che sia proprio utilissimo ma si fa per dire.
import java.awt.*;
public class Lollayout implements LayoutManager {
/* questo metodo è invocato quando al contenitore bersaglio si
richiesta un add(String, Component). Per questo layout non
c'è effetto */
public void addLayoutComponent(String name, Component comp) { }
/* Se alla rimozione di un componente del contenitore un qualche
stato del layout deve mutare... si passa di qui */
public void removeLayoutComponent(Component comp) { }
/* Qui si attribuiscono ai componenti del contenitore le regioni
di spazio da occupare */
public void layoutContainer(Container parent) {
//mo si conta
synchronized(parent.getTreeLock()) {
//Toro seduto tenere sempre conto del bordo
Insets insets = parent.getInsets();
int x0 = insets.left;
int y0 = insets.top;
int width = parent.getWidth() - insets.right - insets.left;
int height = parent.getHeight() - insets.top - insets.bottom;
//(x0, y0, width, height) è l'area effettivamente disponibile
//per la proiezione del contenuto. Inizia la spartizione.
Component[] comps = parent.getComponents();
if(comps.length > 0) {
Component theOne = comps[0];
/* dove ti metto, dove ti metto... lo spariamo nel quadrante
in alto a sinistra */
Rectangle rect = new Rectangle(x0, y0, width / 2, height / 2);
theOne.setBounds(rect);
}
}
}
/** Questo calcola la dimensione preferita del contenitore */
public Dimension preferredLayoutSize(Container parent) {
return minimumLayoutSize(parent); //un bel rinvio di comodo
}
/** Questo calcola la dimensione minima del contenitore */
public Dimension minimumLayoutSize(Container parent) {
synchronized(parent.getTreeLock()) {
Dimension size = new Dimension();
Component[] comps = parent.getComponents();
if(comps.length > 0) {
Dimension compSize = comps[0].getPreferredSize();
//grande il doppio del primo componente...
size.width = compSize.width * 2;
size.height = compSize.height * 2;
}
//Tieni conto del bordo
Insets margini = parent.getInsets();
size.width += margini.left + margini.right;
size.height += margini.top + margini.bottom;
return size;
}
}
}
Ho commentato i passaggi per cui... taccio :D.
Per controllare:
import java.beans.*;
public class RefRunner implements Runnable {
private Statement stat;
public RefRunner(Object ref, String method) {
stat = new Statement(ref, method, null);
}
public void run() {
try {
stat.execute();
} catch(Exception ex) {
throw new RuntimeException(ex);
}
}
}
import java.awt.*;
import javax.swing.*;
public class Main {
public static void main(String[] args) {
RefRunner runner = new RefRunner(new Main(), "start");
SwingUtilities.invokeLater(runner);
}
public void start() {
JPanel panel = new JPanel(new Lollayout());
JButton button = new JButton("Ciao!");
panel.add(button);
JFrame window = new JFrame("Lol");
window.setContentPane(panel);
window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
window.pack();
window.setVisible(true);
}
}
Naturalmente puoi compiere ogni nefandezza che ti salti in mente. Io di solito uso un layout personal-generico con cui divido un contenitore in una griglia – concreta, a differenza di quella virtuale di gridbaglayout – e poi assegno ad ogni pezzo un indice di riga e colonna ed un numero di righe e colonne. Nel tuo caso, ad esempio, dividerei l'interfaccia in 4 righe e 3 colonne per poi assegnare ai due componenti "grossi" una regione di 2x2 celle ciascuno, al componente piccolo una 1x1 e a quello "lungo" un 3x1. Il LayoutManager è questo:
import java.awt.*;
import java.util.*;
public class CustomGridLayout implements LayoutManager {
private int rowCount, columnCount, lineWidth;
private Map<Component, GridData> componentData =
new HashMap<Component, GridData>();
private ComponentList[] rows, columns;
public void addLayoutComponent(String name, Component comp) {}
public void removeLayoutComponent(Component comp) {}
public CustomGridLayout(int rowCount, int columnCount) {
this.lineWidth = lineWidth;
this.rowCount = rowCount;
this.columnCount = columnCount;
initStructures();
}
private void initStructures() {
rows = new ComponentList[rowCount];
columns = new ComponentList[columnCount];
for(int i = 0; i < rows.length; i++) {
rows[i] = new ComponentList();
}
for(int i = 0; i < columns.length; i++) {
columns[i] = new ComponentList();
}
}
public void setComponentData(Component c, GridData d) {
componentData.put(c, d);
for(int i = d.row(); i < d.rows(); i++) {
rows[i].add(c);
}
for(int i = d.column(); i < d.columns(); i++) {
columns[i].add(c);
}
}
public void layoutContainer(Container parent) {
synchronized(parent.getTreeLock()) {
Insets margin = parent.getInsets();
Component[] components = parent.getComponents();
int cellWidth = (parent.getWidth() - margin.left - margin.right) / columnCount;
int cellHeight = (parent.getHeight() - margin.top - margin.bottom) / rowCount;
for(Component c : components) {
GridData data = componentData.get(c);
if(data != null) {
//calcola le dimensioni della regione occupata dal componente
int rx = data.column() * cellWidth + margin.left;
int ry = data.row() * cellHeight + margin.top;
int rw = data.columns() * cellWidth;
int rh = data.rows() * cellHeight;
Rectangle bounds = new Rectangle(rx, ry, rw, rh);
setComponentBounds(c, data, bounds);
}
}
}
}
private void setComponentBounds(Component c, GridData d, Rectangle area) {
Dimension dim = c.getPreferredSize();
if(d.fill() == GridData.NONE) {
int x, y, w, h;
if(dim.width < area.width) {
x = area.x + area.width / 2 - dim.width / 2;
w = dim.width;
} else {
x = area.x;
w = area.width;
}
if(dim.height < area.height) {
y = area.y + area.height / 2 - dim.height / 2;
h = dim.height;
} else {
y = area.y;
h = area.height;
}
Rectangle r = new Rectangle(x, y, w, h);
c.setBounds(r);
} else if(d.fill() == GridData.BOTH) {
c.setBounds(area);
} else if(d.fill() == GridData.VERTICAL) {
int y = area.y;
int h = area.height;
int x, w;
if(dim.width < area.width) {
x = area.x + area.width / 2 - dim.width / 2;
w = dim.width;
} else {
x = area.x;
w = area.width;
}
Rectangle r = new Rectangle(x, y, w, h);
c.setBounds(r);
} else if(d.fill() == GridData.HORIZONTAL) {
int x = area.x;
int w = area.width;
int y, h;
if(dim.height < area.height) {
y = area.y + area.height / 2 - dim.height / 2;
h = dim.height;
} else {
y = area.y;
h = area.height;
}
Rectangle r = new Rectangle(x, y, w, h);
c.setBounds(r);
}
}
public Dimension minimumLayoutSize(Container parent) {
synchronized(parent.getTreeLock()) {
int totalWidth = 0;
//per ogni colonna
for(int i = 0; i < columnCount; i++) {
int maxWidth = 0;
//per ogni componente nella colonna
for(Component c : columns[i]) {
//calcola la larghezza del più largo dei componenti
Dimension dim = c.getPreferredSize();
if(dim.width > maxWidth) maxWidth = dim.width;
}
//somma quella larghezza alla larghezza totale
totalWidth += maxWidth;
}
int totalHeight = 0;
for(int i = 0; i < rowCount; i++) {
int maxHeight = 0;
for(Component c : rows[i]) {
Dimension dim = c.getPreferredSize();
if(dim.height > maxHeight) maxHeight = dim.height;
}
totalHeight += maxHeight;
}
//calcola il lato della cella
int cellWidth = totalWidth / columnCount;
int cellHeight = totalHeight / rowCount;
//usa la dimensione maggiore per determinare le dimensioni del
//componente
int edge = cellWidth > cellHeight ? cellWidth : cellHeight;
int containerWidth = edge * columnCount;
int containerHeight = edge * rowCount;
Insets margin = parent.getInsets();
containerWidth += margin.left + margin.right;
containerHeight += margin.top + margin.bottom;
return new Dimension(containerWidth, containerHeight);
}
}
public Dimension preferredLayoutSize(Container parent) {
return minimumLayoutSize(parent);
}
}
I dati per l'inserimento del componente sono:
import java.awt.*;
public class GridData {
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
public static final int BOTH = 2;
public static final int NONE = 3;
private int row, column, rows, columns;
private int fill = NONE;
public GridData(int row, int column, int rows, int columns, int fill) {
this.row = row;
this.column = column;
this.rows = rows;
this.columns = columns;
this.fill = fill;
}
public int fill() {
return fill;
}
public int row() {
return row;
}
public int column() {
return column;
}
public int rows() {
return rows;
}
public int columns() {
return columns;
}
}
Poi uso un contenitore ad-hoc per semplificare la produzione della griglia:
import java.awt.*;
import javax.swing.*;
public class Grid {
private CustomGridLayout layout;
private JPanel panel;
public Grid(int rowCount, int columnCount) {
layout = new CustomGridLayout(rowCount, columnCount);
panel = new JPanel(layout);
}
public void add(Component c, int row, int column, int rows, int columns, int fill) {
GridData data = new GridData(row, column, rows, columns, fill);
layout.setComponentData(c, data);
panel.add(c);
}
public JComponent panel() {
return panel;
}
}
E l'interfaccia salta fuori con:
import java.awt.*;
import javax.swing.*;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
startUI();
}
});
}
private static void startUI() {
Grid grid = new Grid(4, 3);
grid.add(new JButton("a"), 0, 0, 1, 1, GridData.BOTH);
grid.add(new JButton("b"), 0, 1, 2, 2, GridData.BOTH);
grid.add(new JButton("c"), 1, 0, 3, 1, GridData.BOTH);
grid.add(new JButton("d"), 2, 1, 2, 2, GridData.BOTH);
JFrame f = new JFrame("...");
f.setContentPane(grid.panel());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.pack();
f.setVisible(true);
}
}
Ma è solo un'idea.
Sei stato gentilissimo! Grazie davvero.
Ho un'altra domandina...
C'è un modo per far si che un immagine possa essere vista come un Component e quindi aggiunta tranquillamente ad un pannello come per esempio un bottone un JLabel? ..so che piccole immagini possono essere usate come icone sopra i label..ma se l'immagine è un po' grande non funziona!
Lo chiedo perchè ho dei problemi a procedere diversamente... ecco cosa faccio io:
-mi creo un mio pannello personale dove disegno l'immagine.
import java.awt.*;
import javax.swing.*;
import java.io.*;
import javax.imageio.*;
public class PannelloImmagineGiocatore extends JPanel {
Image image;
public static int sizex;
public static int sizey;
public PannelloImmagineGiocatore(){
try{
image = ImageIO.read(new File("immagini/test.GIF"));
}catch (IOException e){
e.printStackTrace();
}
sizex=image.getHeight(this);
sizey=image.getWidth(this);
this.setSize(sizex,sizey);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
if (image == null) return;
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(image, 0, 0, null);
}
}
e se testo questo codice.. cioè ci metto un bel main con un JFrame e poi inserisco il pannello e provo a far vedere il tutto.. l'ìimmagine si vede!!
Però se poi da un'altra classe mi creo l'oggetto PannelloImmagineGiocatore e lo aggiungo ad un frame.. l'immagine non si vede.. dove sbaglio?
Il pannello che hai creato ha una dimensione preferita di 0x0. Alcuni LayoutManager "se ne fregano" e attribuiscono al pannello una certa regione di spazio, altri la tengono la in considerazione e, in quest'ultimo caso, il tuo pannello non si vedrà.
Quello che puoi fare è stabilire che la dimensione preferita del tuo pannello sia pari alla dimensione del suo bordo più la dimensione dell'immagine e usare un LayoutManager che ne tenga conto nel contenitore in cui quel pannello sarà inserito.
Per la questione della dimensione preferita è sufficiente che tu sovrascriva il metodo getPreferredSize che PannelloImmagineGiocatore riceve da JPanel:
//in PannelloImmagineGiocatore
public Dimension getPreferredSize() {
Insets bordo = getInsets();
int width = image.getWidth(null) + bordo.left + bordo.right;
int height = image.getHeight(null) + bordo.top + bordo.bottom;
return new Dimension(width, height);
}
Per il LayoutManager devi scegliere. Ad esempio FlowLayout, BorderLayout per il componente al centro e GridBagLayout tengono conto della dimensione preferita, GridLayout no.
So che questa non è la sezione giusta per porre questa domanda, ma non so dove chiedere se no.. vorrei aggiungere al mio progetto un bel video poker.. però non so proprio dove reperire le immagini (ad una buona risoluzione) delle carte.. ho provato con google ma invano.. voi sapete indicarmi qualche risorsa? E poi più in generale, quando un programmatore vuole inserire nel suo progetto una determinata grafica che richiede come nel mio caso di immagini specifiche di oggetti... come procede di solito? a colpi di scanner?
Si rivolge a un grafico: un amico grafico, un parente grafico o un professionista grafico, dipende da quello che hai sottomano e dalla natura del progetto.
Come programmatore potresti anche usare quattro scarabocchi autoprodotti. Non è detto che siccome programmi non hai senso artistico: magari hai una dote nascosta e saltano fuori delle carte bellissime. Personalmente non sarei in grado di disegnare neanche il due di picche :D:
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.