java swing - странность макета при использовании разных менеджеров макета - PullRequest
1 голос
/ 12 февраля 2009

Немного странностей, если я сделаю следующее:

import javax.swing.*;
public class FunkyButtonLayout {
    public static void main(String[] args) {
        JFrame frame = new JFrame("");
        JPanel j0 = new JPanel();     // j0 gets added to the root pane
        j0.setLayout(null);
        JPanel j1 = new JPanel();     // j1 gets added to j0 
        j1.setLayout(null);
        JButton b1 = new JButton(""); // b1 gets added to j1
        j1.add(b1);
        b1.setBounds(0, 0, 40, 32);   // b1 is big
        j0.add(j1);
        j1.setBounds(0, 0, 32, 32);   // j1 is not so big - b1 gets 'trimmed'
        frame.getContentPane().setLayout(null); // <- seems to be needed :-(
        frame.getContentPane().add(j0);             
        j0.setBounds(10, 10, 32, 32); // end result: a 32x32 button with
        frame.setSize(125, 125);      // a trimmed right border
        frame.setVisible(true);       // in the top-left corner
    }
}

Я получаю в значительной степени то, что ищу, кроме возможности разместить j0 в корневой панели с помощью менеджера раскладки. Если я изменю

        frame.getContentPane().setLayout(null);

строка до

        frame.getContentPane().setLayout(new java.awt.FlowLayout());

Я вижу j0 в виде пикселя 1x1 в центре экрана: - (

Есть идеи, почему? Обратите внимание, что это не просто вещь FlowLayout - почти каждый менеджер макета испортил это.

Я действительно хочу получить чистый эффект кнопки «обрезать рамку с одной стороны» - она ​​позволяет мне выполнять функцию панели инструментов и кластеров кнопок (такую ​​вещь, которую cage fighter пытается сделать избавиться от) с нативно выглядящими кнопками управления - я не вижу другого способа сделать это, благодаря оболочкам на уровне ОС. Так что любые идеи оценили: -)

Ответы [ 4 ]

4 голосов
/ 12 февраля 2009

Если вы зададите для диспетчера макета значение null, вам придется явно указать предпочтительный размер контейнера (поэтому он так мал).

Если вы используете setBounds для компонента, вы перезаписываете работу, которую выполняет менеджер макета для родительского контейнера.

Я бы удалил все вызовы setBounds и все вызовы setLayout (null) и попытался бы добиться желаемого эффекта после использования только менеджеров компоновки.

1 голос
/ 13 февраля 2009

Для действительно хорошего объяснения того, как работают менеджеры по расположению, прочитайте старую статью, которую я написал в Sun

http://developer.java.sun.com/developer/onlineTraining/GUI/AWTLayoutMgr/

Он старый, но довольно хорошо говорит о предпочтительном размере и раскладке макета.

Наслаждайтесь, - Скотт

1 голос
/ 12 февраля 2009

... есть идеи почему?

Да. Это происходит потому, что когда вы удаляете менеджер раскладки (устанавливая его на ноль), вы говорите компьютеру: «Я приму все работы по укладке»; при использовании любого другого LayoutManager попытается ... хорошо расположить ваши компоненты в соответствии с вашими потребностями (в зависимости от свойств объектов, которые будут уложены)

Итак, я думаю, что было бы гораздо лучше вместо этого попытаться создать экземпляр Border и установить его в JButton, а не пытаться настроить все объекты вокруг него.

Я посмотрю, смогу ли я придумать что-нибудь быстро.

EDIT:

Упс, это было не так быстро, но вот оно (я испортил линию 1px, которая меня раздражала) альтернативный текст http://img22.imageshack.us/img22/8933/capturaby8.png

Как я уже говорил, установка макета на нуль - не лучший подход. Лучше создать пользовательскую границу и установить ее для кнопки (или установить нулевую границу).

Вот код:

import javax.swing.*;
import java.awt.*;
import javax.swing.border.*;
import java.awt.geom.*;

/**
 * Sample usage of swing borders.
 * @author <a href="http://stackoverflow.com/users/20654">Oscar Reyes</a>
 */
public class ButtonBorderSample  { 

    public static void main( String [] args )  { 

        // Pretty standard swing code
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );


        JPanel panel  = new JPanel( new FlowLayout( 
                                       FlowLayout.CENTER, 0, 5 ) );


        panel.add( createButton( "F I R S T" ) );
        panel.add( createButton( "S E C O N D" ) );
        panel.add( createButton( "T H I R D " ) );

        frame.add( panel , BorderLayout.NORTH );

        frame.pack();
        frame.setVisible( true );

    }
    /**
     * Utility method to create a button.
     * Creates the button, make it square, and add our custom border.
     */
    private static JButton createButton( String s ) { 
        JButton b = new JButton( s );
        b.setPreferredSize( new Dimension( 100, 100   ) );
        b.setBorder( new NoGapBorder() );
        return b;
    }
}

/**
 * This border implementation. It doesn't have insets and draws only a 
 * few parts of the border 
 * @author <a href="http://stackoverflow.com/users/20654">Oscar Reyes</a>
 */
class NoGapBorder implements Border  {

    private final Insets insets = new Insets( -1, -1 , -1, -1 );

    /** 
     * Defines in Border interface.
     * @return The default insets instace that specifies no gap at all.
     */
    public Insets getBorderInsets(Component c ) {
        return insets;
    }


    /** 
     * Defines in Border interface.
     * @return false always, it is not relevant.
     */
    public boolean isBorderOpaque() { 
        return false;
    }

    /**
     * Paint the border for the button. 
     * This creates the difference between setting the border to null 
     * and using this class. 
     * It only draws a line in the top, a line in the bottom and a 
     * darker line 
     * in the left, to create the desired effect.
     * A much more complicated strtegy could be used here.
     */
    public void paintBorder(Component c, Graphics g, 
                            int x, int y, int width, int height) { 

       Color oldColor = g.getColor();
       int h = height;
       int w = width;

       g.translate(x, y);

        // Color for top and bottom
        g.setColor( c.getBackground().brighter() );

        // draw top line
        g.drawLine(1, 0, w-2, 0);

        // draw bottom line
       g.drawLine(0, h-1, w-1, h-1); 

       // change the color to make it look as a division
       g.setColor( c.getBackground().darker() );

       // draw the left line
       g.drawLine(0, 0, 0, h-2);        

        // set the graphics back to its original state.
       g.translate(-x, -y);
       g.setColor(oldColor);

    }

}

РЕДАКТИРОВАТЬ

Дейв Карпенето писал:

** Оскар> *** К сожалению, это перестает работать, как только вы UIManager.setLookAndFeel (UIManager.getSystemLookAndFeelClassName ()); , и это также было основой для моих потребностей (я хочу, чтобы это выглядело как можно более естественным). *

Ну, я не пытался сделать вашу работу, но чтобы ответить на ваш вопрос, вы подумали, что ваши проблемы связаны с LayoutManagers, и я сказал, что это не проблема.

Возможно, мне следовало остановиться на этом, но мой «программистский» зуд заставил меня продолжить выборку. :)

Я рад, что вы решили свою проблему в конце;)

0 голосов
/ 13 февраля 2009

Привет - спасибо всем за помощь.

Dan> именно ваш комментарий о предпочтительном макете заставил меня заставить это работать - добавление j0.setPreferredSize(new java.awt.Dimension(32, 32)); было всем, что было необходимо, чтобы заставить это работать.

Оскар> К сожалению, это перестает работать, как только вы UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());, и это также было основным для моих нужд (я хочу сделать этот вид как можно более естественным).

Например, вот как выглядит мой с 3 кнопками на XP:

альтернативный текст http://img19.imageshack.us/img19/8595/minems5.png

... и вот как выглядит ваш внешний вид с XP:

альтернативный текст http://img102.imageshack.us/img102/5412/yoursod4.png

... что, к сожалению, не одно и то же - извините, что не уточнил мои требования: - (

FWIW, вот код (изображения представляют собой прозрачные значки того же размера, что и кнопки, с вертикальными линиями как частью значка):

import java.awt.*;
import javax.swing.*;

public class FunkyButtonLayout {
  public static void main(String[] args) {
    try {
        UIManager.setLookAndFeel(
          UIManager.getSystemLookAndFeelClassName());
    } catch (Exception e) {

    }

    JFrame frame = new JFrame("x");
    Container y = frame.getContentPane();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    y.setLayout(new FlowLayout());

    JPanel uberButton = new JPanel();
    uberButton.setLayout(null);
    uberButton.setSize(98, 32);
    uberButton.setPreferredSize(new Dimension(98, 32));

    JButton record = new JButton(new ImageIcon("img/record.png"));
    record.setBounds(0, 0, 40, 32);
    record.setEnabled(true);
    record.setFocusPainted(false);
    JPanel _record = new JPanel();
    _record.setLayout(null);
    _record.setBounds(0, 0, 33, 32);

    JButton pause = new JButton(new ImageIcon("img/pause.png"));
    pause.setBounds(-4, 0, 44, 32);
    pause.setEnabled(true);
    pause.setFocusPainted(false);
    JPanel _pause = new JPanel();
    _pause.setLayout(null);
    _pause.setBounds(33, 0, 33, 32);

    JButton stop = new JButton(new ImageIcon("img/stop.png"));
    stop.setBounds(-4, 0, 36, 32);
    stop.setEnabled(true);
    stop.setFocusPainted(false);
    JPanel _stop = new JPanel();
    _stop.setLayout(null);
    _stop.setBounds(66, 0, 32, 32); 

    _record.add(record);
    _pause.add(pause);
    _stop.add(stop);

    uberButton.add(_record);
    uberButton.add(_pause);
    uberButton.add(_stop);

    y.add(uberButton);

    frame.pack();

    frame.setVisible(true);

  }
}

Скотт> Я получил образование :-) спасибо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...