Java Swing GridBagLayout не соответствует ожиданиям

Почему-то я не могу заставить работать сетку в GridBagLayout в моем простом приложении SwingApp.

У меня есть этот код в Java Swing:

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.Border;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;

class GridBagLayt extends JFrame {
 
    GridBagLayt()
    {
        JButton jb1 = new JButton("1");
        JButton jb2 = new JButton("2");
        JButton jb3 = new JButton("3");
        JButton jb4 = new JButton("4");
        JButton jb5 = new JButton("5");
        
        GridBagLayout lay = new GridBagLayout();
        GridBagConstraints cons = new GridBagConstraints();
        
        setLayout(lay);
        cons.fill = GridBagConstraints.BOTH;
        cons.gridheight = 1;
        cons.weightx = 1;
        cons.weighty = 1;


        cons.gridx = 0; cons.gridy = 0; 
        cons.gridwidth = 2;
        lay.setConstraints(jb1, cons);
        add(jb1);
        
        cons.gridx = 2; 
        lay.setConstraints(jb2, cons);
        add(jb2);
         
        cons.gridx = 0; cons.gridy = 1; 
        cons.gridwidth = 1;
        lay.setConstraints(jb3, cons);
        add(jb3);
        
        cons.gridx = 1;
        cons.gridwidth = 2;
        lay.setConstraints(jb4, cons);
        add(jb4);
        
        cons.gridx = 3;
        cons.gridwidth = 1;
        lay.setConstraints(jb5, cons);
        add(jb5);
        
        
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(700,200);
        setVisible(true);
    }
  }

    public class SwingApp {
 
        public static void main(String[] args) {
     
            new GridBagLayt();
        }
    }

Вот что я хочу получить:

Но вместо этого я получаю это:

Я действительно не знаю, в чем проблема, мне кажется, что координаты и ширина сетки в порядке, и я ожидал, что это сработает, но это не так. И если я добавлю еще четыре кнопки между этими двумя строками, то третья строка выглядит нормально, но я этого не хочу:

Пример: если я добавлю этот код

cons.gridx = 0; cons.gridy = 0; 
        cons.gridwidth = 2;
        lay.setConstraints(jb1, cons);
        add(jb1);
        
        cons.gridx = 2; 
        lay.setConstraints(jb2, cons);
        add(jb2);
        
        
        cons.gridx = 0; cons.gridy = 1; 
        cons.gridwidth = 1;
        lay.setConstraints(jb3, cons);
        add(jb3);
        
        cons.gridx = 1;
        lay.setConstraints(jb4, cons);
        add(jb4);
        
        cons.gridx = 2;
        lay.setConstraints(jb5, cons);
        add(jb5);
      
        cons.gridx = 3;
        lay.setConstraints(jb6, cons);
        add(jb6);
        
        cons.gridx = 0; cons.gridy = 2; 
        lay.setConstraints(jb7, cons);
        add(jb7);
        
        
        cons.gridx = 1; cons.gridy = 2; 
        cons.gridwidth = 2;
        lay.setConstraints(jb8, cons);
        add(jb8);
        
        cons.gridx = 3; cons.gridy = 2; 
        cons.gridwidth = 1;
        lay.setConstraints(jb9, cons);
        add(jb9);

Затем я получил это:

Но я не хочу этого второго ряда

Почему вы добавляете ячейки, которые вам не нужны?

Just another Java programmer 16.05.2023 12:08

просто чтобы показать, что это работает, если они есть (я нашел это где-то в Интернете и хотел использовать его без второго ряда, и он не работает)

Ewe 16.05.2023 12:18

Я бы начал с добавления 1 и 2 в отдельный контейнер

MadProgrammer 16.05.2023 12:38

GridBagLayouts никогда не бывают такими, как ожидалось ;) Вам действительно следует взглянуть на другой менеджер компоновки, такой как MigLayout.

Emmanuel Bourg 16.05.2023 15:11
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
4
72
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Наконец-то я заставил этот графический интерфейс работать, но мне пришлось использовать два хака, которые я не рекомендую использовать.

У Oracle есть полезный учебник Создание графического интерфейса с помощью Swing. Пропустите раздел Изучение Swing с помощью среды IDE NetBeans.

Причина, по которой этот графический интерфейс трудно реализовать, заключается в том, что GridBagLayout не нужно использовать для определения размера четырех столбцов. Итак, заимствуя из ОП, я создал пустую строку JLabels перед созданием строк JButtons. Я выбрал размер JLabels исходя из размера JButton.

Я не был уверен, пока не попробовал, но gridheight, равный нулю, удерживает JLabels в том же физическом месте, что и первая строка JButtons.

Вот полный, уродливый, исполняемый код.

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class GridBagLayoutTest2 implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new GridBagLayoutTest2());
    }

    @Override
    public void run() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.add(createPanels(), BorderLayout.CENTER);

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

    private JPanel createPanels() {
        JPanel panel = new JPanel(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.anchor = GridBagConstraints.LINE_START;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.insets = new Insets(5, 5, 5, 5);
        gbc.weightx = 0.0;
        
        JButton button1 = new JButton("Button 1");
        Dimension d = button1.getPreferredSize();
        
        gbc.gridheight = 0;
        gbc.gridwidth = 1;
        gbc.gridx = 0;
        gbc.gridy = 0;
        for (int index = 0; index < 4; index++) {
            JLabel label = new JLabel();
            label.setPreferredSize(d);
            panel.add(label, gbc);
            gbc.gridx++;
        }

        gbc.gridheight = 1;
        gbc.gridwidth = 2;
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.weightx = 1.0;
        panel.add(button1, gbc);
        
        gbc.gridx += 2;
        JButton button2 = new JButton("Button 2");
        panel.add(button2, gbc);
        
        gbc.gridwidth = 1;
        gbc.gridx = 0;
        gbc.gridy++;
        JButton button3 = new JButton("Button 3");
        panel.add(button3, gbc);
        
        gbc.gridwidth = 2;
        gbc.gridx += 1;
        JButton button4 = new JButton("Button 4");
        panel.add(button4, gbc);
        
        gbc.gridwidth = 1;
        gbc.gridx += 2;
        JButton button5 = new JButton("Button 5");
        panel.add(button5, gbc);

        return panel;
    }

}

Я пытался добавить панели/метки с высотой 0 во второй ряд, и это не сработало (между второй и третьей строками все еще был пробел), но это работает, также я попытался добавить 4 метки и первые две кнопки на y=0 и это тоже нормально. Но теперь мне любопытно, почему это не рекомендуется?

Ewe 16.05.2023 13:59

*Моя ошибка, это также работает с добавлением меток с высотой 0 во второй строке

Ewe 16.05.2023 14:05

@Ewe: Эти типы взломов приводят к тому, что код, который трудно поддерживать, трудно корректно модифицировать, ломается загадочным образом. На этом простом примере вы можете понять, что происходит. В 100 JPanel графическом интерфейсе это не так очевидно.

Gilbert Le Blanc 16.05.2023 14:08

Причина, по которой этот графический интерфейс трудно реализовать, заключается в том, что GridBagLayout не имеет ничего общего с размером четырех столбцов. Я опубликовал ответ, показывающий, как использовать свойства GridBagLayout без создания дополнительных компонентов.

camickr 17.05.2023 00:25
Ответ принят как подходящий

Любой подходящий сложный пользовательский интерфейс/макет должен быть разделен на несколько компонентов. Это широко известно как «составные макеты».

Это позволяет лучше сосредоточиться на индивидуальных потребностях каждой «области» макета независимо.

Иногда нужно просто притвориться.

Обратите внимание, что я использовал метки вместо кнопок только для демонстрации, так как вокруг кнопок MacOs много места, и это лучше иллюстрирует использование GridBagConstraints#insets

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.weightx = 1;
            gbc.fill = gbc.HORIZONTAL;
            gbc.insets = new Insets(4, 0, 4, 0);
            gbc.gridwidth = GridBagConstraints.REMAINDER;

            add(makeFirstRow(), gbc);
            add(makeSecondRow(), gbc);
            add(makeThirdRow(), gbc);
        }

        protected JLabel makeLabel(String text) {
            JLabel label = new JLabel(text);
            label.setHorizontalAlignment(JLabel.CENTER);
            label.setOpaque(true);
            label.setBackground(Color.RED);
            label.setBorder(new EmptyBorder(8, 32, 8, 32));
            return label;
        }

        protected JPanel makeFirstRow() {
            JPanel rowPane = new JPanel(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.weightx = 1;
            gbc.fill = gbc.HORIZONTAL;
            gbc.insets = new Insets(0, 4, 0, 4);

            rowPane.add(makeLabel("1"), gbc);
            rowPane.add(makeLabel("2"), gbc);

            return rowPane;
        }

        protected JPanel makeSecondRow() {
            JPanel rowPane = new JPanel(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.weightx = 1;
            gbc.fill = gbc.HORIZONTAL;
            gbc.insets = new Insets(0, 4, 0, 4);

            rowPane.add(makeLabel("3"), gbc);
            rowPane.add(makeLabel("4"), gbc);
            rowPane.add(makeLabel("5"), gbc);

            return rowPane;
        }

        protected JPanel makeThirdRow() {
            JPanel rowPane = new JPanel(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.weightx = 1;
            gbc.fill = gbc.HORIZONTAL;
            gbc.insets = new Insets(0, 4, 0, 4);

            rowPane.add(makeLabel("6"), gbc);
            rowPane.add(makeLabel("7"), gbc);
            rowPane.add(makeLabel("8"), gbc);

            return rowPane;
        }
    }

}

Не знаю, как у вас, а у меня возник соблазн создать какой-нибудь фабричный метод, который бы создавал каждую строку на основе количества элементов, которые мне нужны в каждой строке... но это я 😉

но с немного другой компоновкой. кнопка 4 (и 7 в вашем макете) должны быть такого же размера, как кнопки 1 и 2, но в вашем случае они составляют 2/3 размера 1 и 2, а кнопки 3 и 5 должны быть 1/2 от 1 и 2 , а тут их 2/3

Затем измените свойство столбцов weightx соответствующим образом, например...

protected JPanel makeSecondRow() {
    JPanel rowPane = new JPanel(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.fill = gbc.HORIZONTAL;
    gbc.insets = new Insets(0, 4, 0, 4);

    gbc.weightx = 0.25;
    rowPane.add(makeLabel("3"), gbc);
    gbc.weightx = 0.5;
    // This is simply adding an addition padding to the
    // labels preferred size, otherwise all three buttons
    // can be layed out at there preferred size with the
    // avaliable space
    gbc.ipadx = 64;
    rowPane.add(makeLabel("4"), gbc);
    gbc.weightx = 0.25;
    gbc.ipadx = 0;
    rowPane.add(makeLabel("5"), gbc);

    return rowPane;
}

Теперь помните, что в этом играет роль предпочтительный размер компонентов. Без дополнительного ipadx все три элемента можно разместить в нужном размере в доступной области контейнера.

И нет, вам не нужно указывать weightx для каждого столбца, это просто демонстрация, но иногда вам может быть полезнее быть абсолютным в своих желаниях.

это выглядит красиво, но с немного другим расположением. кнопка 4 (и 7 в вашем макете) должны быть такого же размера, как кнопки 1 и 2, но в вашем случае они составляют 2/3 размера 1 и 2, а кнопки 3 и 5 должны быть 1/2 от 1 и 2 , а здесь их 2/3. В любом случае, информация о том, что лучше использовать несколько компонентов, полезна, спасибо

Ewe 16.05.2023 13:56

@Ewe Затем измените свойства weightx соответствующим образом, но имейте в виду, что предпочтительный размер каждого компонента повлияет на макет, поскольку все три элемента в строке имеют одинаковый предпочтительный размер, они могут быть размещены в одном размере.

MadProgrammer 16.05.2023 14:12

Вот это здорово. Еще один вопрос: при установке weightx для ячеек в одном компоненте я должен сделать так, чтобы они всегда суммировались до 1? (например, как в вашем случае 0,25, 0,5, 0,25)

Ewe 16.05.2023 14:23

@ Эве нет, не надо. В моем исходном примере я сделал их все равными единице, поэтому оставшееся доступное пространство было разделено между ними поровну. Вы можете обнаружить, что вам нужно указать только среднюю кнопку, но бывают случаи, когда вы хотите, чтобы ваши желания были очень четкими.

MadProgrammer 16.05.2023 23:20

Я бы использовал один дополнительный JPanel для каждой строки, и не стал бы расширять JFrame (без необходимости, то есть добавляя к нему функциональность)):

public class SwingApp2 {
    
    public static void main(String[] args) {
        SwingUtilities.invokeLater(SwingApp2::new);
    }

    private SwingApp2()
    {
        var jb1 = new JButton("1");
        var jb2 = new JButton("2");
        var jb3 = new JButton("3");
        var jb4 = new JButton("4");
        var jb5 = new JButton("5");

        var line1 = new JPanel(new GridBagLayout());
        var gbc = new GridBagConstraints(RELATIVE, 0, 1, 1, 1.0, 1.0, CENTER, BOTH, new Insets(0, 0, 0, 0), 0, 0);
        line1.add(jb1, gbc);
        line1.add(jb2, gbc);

        var line2 = new JPanel(new GridBagLayout());
        line2.add(jb3, gbc);
        gbc.weightx *= 2;
        line2.add(jb4, gbc);
        gbc.weightx /= 2;
        line2.add(jb5, gbc);

        var frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        // using GridLayout so the lines are same height
        frame.setLayout(new GridLayout(0, 1));
        frame.add(line1);
        frame.add(line2);
        frame.setSize(700,200);
        frame.setVisible(true);
    }
}

Результат:

Just one way to do it, very dependent of how the components should be resized if the GUI size is changed
Also be aware that sizes will change according to preferred size, that is, labels content

GridBagLayout занимается выравниванием, а не пропорциями. Иногда его можно использовать для компоновки компонентов одинакового размера, но в этом он не очень хорош.

SpringLayout, однако, довольно хорош в этом, и у него есть специальные методы для этого. Компромисс заключается в том, что SpringLayout сложно использовать и легко использовать неправильно. Он работает как «макеты форм» 1990-х годов. Для каждого компонента в макете вы должны указать, где должен располагаться хотя бы один горизонтальный край и один вертикальный край относительно краев контейнера или относительно краев других дочерних компонентов.

Во-первых, лучше создать свой контейнер, а не расширять JFrame. Нет смысла создавать подкласс JFrame, поскольку вы просто используете JFrame, не меняя его поведения:

SpringLayout layout = new SpringLayout();
JPanel panel = new JPanel(layout);

Далее, давайте вычислим согласованный размер для маленьких кнопок:

JButton[] buttons = { jb1, jb2, jb3, jb4, jb5 };

Spring width = Spring.constant(0);
Spring height = Spring.constant(0);
for (JButton button : buttons) {
    width = Spring.max(width, Spring.width(button));
    height = Spring.max(height, Spring.height(button));
}

Далее сделаем кнопки 1, 2 и 4 в два раза шире:

Spring largeButtonWidth = Spring.scale(width, 2);

Теперь мы можем использовать эти Springs для создания ограничений для каждой кнопки:

Spring zero = Spring.constant(0);

panel.add(jb1, new SpringLayout.Constraints(
    zero, zero, largeButtonWidth, height));

panel.add(jb2, new SpringLayout.Constraints(
    largeButtonWidth, zero, largeButtonWidth, height));

panel.add(jb3, new SpringLayout.Constraints(
    zero, height, width, height));

panel.add(jb4, new SpringLayout.Constraints(
    width, height, largeButtonWidth, height));

panel.add(jb5, new SpringLayout.Constraints(
    Spring.sum(width, largeButtonWidth), height, width, height));

Наконец, нам нужно сообщить макету, насколько большим должен быть сам контейнер. Он должен быть достаточно широким, чтобы вместить jb2 и jb5, и достаточно высоким, чтобы вместить jb3, jb4 и jb5. Мы могли бы использовать любой из них, чтобы указать предпочтительный размер контейнера, но jb5, вероятно, самый простой выбор:

layout.putConstraint(
    SpringLayout.EAST, panel, 0, SpringLayout.EAST, jb5);
layout.putConstraint(
    SpringLayout.SOUTH, panel, 0, SpringLayout.SOUTH, jb5);

Собранное все вместе выглядит так:

import java.awt.EventQueue;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.Spring;
import javax.swing.SpringLayout;

public class RelativeButtonSizesDemo {
    private final JFrame frame;

    public RelativeButtonSizesDemo() {
        JButton jb1 = new JButton("1");
        JButton jb2 = new JButton("2");
        JButton jb3 = new JButton("3");
        JButton jb4 = new JButton("4");
        JButton jb5 = new JButton("5");

        JButton[] buttons = { jb1, jb2, jb3, jb4, jb5 };

        Spring width = Spring.constant(0);
        Spring height = Spring.constant(0);
        for (JButton button : buttons) {
            width = Spring.max(width, Spring.width(button));
            height = Spring.max(height, Spring.height(button));
        }

        // jb1, jb2, and jb4 will be twice as wide as the other buttons.
        Spring largeButtonWidth = Spring.scale(width, 2);

        SpringLayout layout = new SpringLayout();
        JPanel panel = new JPanel(layout);

        Spring zero = Spring.constant(0);

        panel.add(jb1, new SpringLayout.Constraints(
            zero, zero, largeButtonWidth, height));

        panel.add(jb2, new SpringLayout.Constraints(
            largeButtonWidth, zero, largeButtonWidth, height));

        panel.add(jb3, new SpringLayout.Constraints(
            zero, height, width, height));

        panel.add(jb4, new SpringLayout.Constraints(
            width, height, largeButtonWidth, height));

        panel.add(jb5, new SpringLayout.Constraints(
            Spring.sum(width, largeButtonWidth), height, width, height));

        // Set preferred size of panel itself to accommodate buttons.
        layout.putConstraint(
            SpringLayout.EAST, panel, 0, SpringLayout.EAST, jb5);
        layout.putConstraint(
            SpringLayout.SOUTH, panel, 0, SpringLayout.SOUTH, jb5);

        frame = new JFrame("Relative Button Sizes Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(panel);
        frame.pack();
        frame.setLocationByPlatform(true);
    }

    public void show() {
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> new RelativeButtonSizesDemo().show());
    }
}

Причина, по которой этот графический интерфейс трудно реализовать, заключается в том, что GridBagLayout не имеет ничего общего с размером четырех столбцов.

GridBagLayout имеет свойства, которые позволяют вам определять значения по умолчанию для столбцов, которые не имеют компонентов, как показано ниже:

import java.util.*;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class GridBagLayoutTest3 implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new GridBagLayoutTest3());
    }

    @Override
    public void run() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.add(createPanels(), BorderLayout.CENTER);

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

    private JPanel createPanels() {

        //  Create the GridBagLayout and GridBagConstraints to be used by the panel

        GridBagLayout gbl = new GridBagLayout();
        JPanel panel = new JPanel(gbl);

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.anchor = GridBagConstraints.LINE_START;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.insets = new Insets(5, 5, 5, 5);

        //  Create and add components to the panel

        JButton button1 = new JButton("Button 1");
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 2;
        panel.add(button1, gbc);

        gbc.gridx += 2;
        JButton button2 = new JButton("Button 2");
        panel.add(button2, gbc);

        gbc.gridwidth = 1;
        gbc.gridx = 0;
        gbc.gridy++;
        JButton button3 = new JButton("Button 3");
        panel.add(button3, gbc);

        gbc.gridwidth = 2;
        gbc.gridx += 1;
        JButton button4 = new JButton("Button 4");
        panel.add(button4, gbc);

        gbc.gridwidth = 1;
        gbc.gridx += 2;
        JButton button5 = new JButton("Button 5");
        panel.add(button5, gbc);

        //  Set properties of the GridBagLayout for columns without components in a single column

        int[] columns = new int[4];
        Arrays.fill(columns, button1.getPreferredSize().width);
        gbl.columnWidths = columns;
        double[] weights = new double[4];
        Arrays.fill(weights, 1.0);
        gbl.columnWeights = weights;

        return panel;
    }

}

Примечание: вы также можете проверить: https://stackoverflow.com/a/57463596/131872, где есть более сложный пример, показывающий, как использовать этот подход для «клавиатурной» раскладки кнопок.

Другие вопросы по теме