이 페이지에서

계산기 예제

이 예제는 신호와 슬롯을 사용하여 계산기 위젯의 기능을 구현하는 방법과, 그리드 레이아웃( QGridLayout )을 사용하여 자식 위젯을 그리드에 배치하는 방법을 보여줍니다.

기본 계산기 앱

계산기 예제의 스크린샷

이 예제는 두 개의 클래스로 구성되어 있습니다:

  • Calculator 는 모든 계산기 기능을 갖춘 계산기 위젯입니다.
  • Button 는 계산기의 각 버튼에 사용되는 위젯입니다. 이 클래스는 ` QToolButton`에서 파생됩니다.

먼저 ` Calculator`을 살펴본 다음, ` Button`을 살펴보겠습니다.

Calculator 클래스 정의

class Calculator : public QWidget
{
    Q_OBJECT

public:
    Calculator(QWidget *parent = nullptr);

private slots:
    void digitClicked();
    void unaryOperatorClicked();
    void additiveOperatorClicked();
    void multiplicativeOperatorClicked();
    void equalClicked();
    void pointClicked();
    void changeSignClicked();
    void backspaceClicked();
    void clear();
    void clearAll();
    void clearMemory();
    void readMemory();
    void setMemory();
    void addToMemory();

Calculator 클래스는 간단한 계산기 위젯을 제공합니다. 이 클래스는 QDialog 을 상속받으며, 계산기 버튼과 관련된 여러 개의 비공개 슬롯을 가지고 있습니다. QObject::eventFilter()은 계산기 화면에서 발생하는 마우스 이벤트를 처리하기 위해 재구현되었습니다.

버튼은 동작에 따라 범주로 그룹화됩니다. 예를 들어, 모든 숫자 버튼( 0 부터 9 까지)은 현재 피연산자에 숫자를 추가합니다. 이러한 버튼의 경우, 여러 버튼을 동일한 슬롯(예: digitClicked())에 연결합니다. 범주로는 숫자, 단항 연산자(Sqrt, x², 1/x), 덧셈 연산자(+, -), 곱셈 연산자(×, ÷)가 있습니다. 그 외의 버튼들은 각각 고유한 슬롯을 갖습니다.

private:
    template<typename PointerToMemberFunction>
    Button *createButton(const QString &text, const PointerToMemberFunction &member);
    void abortOperation();
    bool calculate(double rightOperand, const QString &pendingOperator);

비공개 함수 ` createButton() `는 위젯 생성 과정의 일부로 사용됩니다. ` abortOperation() `는 0으로 나눗셈이 발생하거나 음수에 제곱근 연산이 적용될 때마다 호출됩니다. ` calculate() `는 이항 연산자(`+`, ` -`, ` ×` 또는 ` ÷`)를 적용합니다.

    double sumInMemory;
    double sumSoFar;
    double factorSoFar;
    QString pendingAdditiveOperator;
    QString pendingMultiplicativeOperator;
    bool waitingForOperand;

이러한 변수들은 계산기 디스플레이의 내용( QLineEdit)과 함께 계산기의 상태를 나타냅니다:

  • sumInMemory 는 계산기 메모리에 저장된 값을 포함합니다( MS, M+ 또는 MC 를 사용하여).
  • sumSoFar 지금까지 누적된 값을 저장합니다. 사용자가 ‘ = ’를 클릭하면 ‘ sumSoFar ’가 재계산되어 디스플레이에 표시됩니다. ‘ Clear All ’는 ‘ sumSoFar ’를 0으로 재설정합니다.
  • factorSoFar 곱셈 및 나눗셈 연산을 수행할 때 임시 값을 저장합니다.
  • pendingAdditiveOperator 사용자가 마지막으로 클릭한 덧셈 연산자를 저장합니다.
  • pendingMultiplicativeOperator 사용자가 마지막으로 클릭한 곱셈 연산자를 저장합니다.
  • waitingForOperand 계산기가 사용자가 피연산자 입력을 시작하기를 기다릴 때 true 상태입니다.

덧셈 연산자와 곱셈 연산자는 우선순위가 다르기 때문에 다르게 처리됩니다. 예를 들어, 1 + 2 ÷ 3 는 1 + (2 ÷ 3) 로 해석되는데, 이는 ÷ 가 + 보다 우선순위가 높기 때문입니다.

아래 표는 사용자가 수학 식을 입력함에 따라 계산기의 상태가 어떻게 변화하는지를 보여줍니다.

사용자 입력표시현재 합계덧셈 연산현재까지의 인자곱셈 연산연산 대상 기다림?
00true
110false
1 +11+true
1 + 221+false
1 + 2 ÷21+2÷true
1 + 2 ÷ 331+2÷false
1 + 2 ÷ 3 -1.666671.66667-true
1 + 2 ÷ 3 - 441.66667-false
1 + 2 ÷ 3 - 4 =-2.333330true

Sqrt 와 같은 단항 연산자는 특별한 처리가 필요하지 않습니다. 연산자 버튼을 클릭할 때 피연산자가 이미 알려져 있으므로 즉시 적용할 수 있습니다.

    QLineEdit *display;

    enum { NumDigitButtons = 10 };
    Button *digitButtons[NumDigitButtons];
};

마지막으로, 숫자를 표시하는 데 사용되는 디스플레이 및 버튼과 관련된 변수들을 선언합니다.

Calculator 클래스 구현

Calculator::Calculator(QWidget *parent)
    : QWidget(parent), sumInMemory(0.0), sumSoFar(0.0)
    , factorSoFar(0.0), waitingForOperand(true)
{

생성자에서 계산기의 상태를 초기화합니다. ` pendingAdditiveOperator ` 및 ` pendingMultiplicativeOperator ` 변수는 ` QString ` 생성자가 이를 빈 문자열로 초기화하므로 명시적으로 초기화할 필요가 없습니다. 또한 헤더 파일에서 해당 변수를 직접 초기화할 수도 있습니다. 이를 ` member-initializaton `라고 하며, 긴 초기화 목록을 피할 수 있습니다.

    display = new QLineEdit("0");
    display->setReadOnly(true);
    display->setAlignment(Qt::AlignRight);
    display->setMaxLength(15);

    QFont font = display->font();
    font.setPointSize(font.pointSize() + 8);
    display->setFont(font);

계산기의 디스플레이를 나타내는 ` QLineEdit ` 객체를 생성하고, 몇 가지 속성을 설정합니다. 특히, 이 객체를 읽기 전용으로 설정합니다.

또한 display 의 글꼴 크기를 8포인트로 늘립니다.

    for (int i = 0; i < NumDigitButtons; ++i)
        digitButtons[i] = createButton(QString::number(i), &Calculator::digitClicked);

    Button *pointButton = createButton(tr("."), &Calculator::pointClicked);
    Button *changeSignButton = createButton(tr("\302\261"), &Calculator::changeSignClicked);

    Button *backspaceButton = createButton(tr("Backspace"), &Calculator::backspaceClicked);
    Button *clearButton = createButton(tr("Clear"), &Calculator::clear);
    Button *clearAllButton = createButton(tr("Clear All"), &Calculator::clearAll);

    Button *clearMemoryButton = createButton(tr("MC"), &Calculator::clearMemory);
    Button *readMemoryButton = createButton(tr("MR"), &Calculator::readMemory);
    Button *setMemoryButton = createButton(tr("MS"), &Calculator::setMemory);
    Button *addToMemoryButton = createButton(tr("M+"), &Calculator::addToMemory);

    Button *divisionButton = createButton(tr("\303\267"), &Calculator::multiplicativeOperatorClicked);
    Button *timesButton = createButton(tr("\303\227"), &Calculator::multiplicativeOperatorClicked);
    Button *minusButton = createButton(tr("-"), &Calculator::additiveOperatorClicked);
    Button *plusButton = createButton(tr("+"), &Calculator::additiveOperatorClicked);

    Button *squareRootButton = createButton(tr("Sqrt"), &Calculator::unaryOperatorClicked);
    Button *powerButton = createButton(tr("x\302\262"), &Calculator::unaryOperatorClicked);
    Button *reciprocalButton = createButton(tr("1/x"), &Calculator::unaryOperatorClicked);
    Button *equalButton = createButton(tr("="), &Calculator::equalClicked);

각 버튼에 대해, 적절한 텍스트 레이블과 버튼에 연결할 슬롯을 인수로 전달하여 비공개 ` createButton() ` 함수를 호출합니다.

    QGridLayout *mainLayout = new QGridLayout;
    mainLayout->setSizeConstraint(QLayout::SetFixedSize);
    mainLayout->addWidget(display, 0, 0, 1, 6);
    mainLayout->addWidget(backspaceButton, 1, 0, 1, 2);
    mainLayout->addWidget(clearButton, 1, 2, 1, 2);
    mainLayout->addWidget(clearAllButton, 1, 4, 1, 2);

    mainLayout->addWidget(clearMemoryButton, 2, 0);
    mainLayout->addWidget(readMemoryButton, 3, 0);
    mainLayout->addWidget(setMemoryButton, 4, 0);
    mainLayout->addWidget(addToMemoryButton, 5, 0);

    for (int i = 1; i < NumDigitButtons; ++i) {
        int row = ((9 - i) / 3) + 2;
        int column = ((i - 1) % 3) + 1;
        mainLayout->addWidget(digitButtons[i], row, column);
    }

    mainLayout->addWidget(digitButtons[0], 5, 1);
    mainLayout->addWidget(pointButton, 5, 2);
    mainLayout->addWidget(changeSignButton, 5, 3);

    mainLayout->addWidget(divisionButton, 2, 4);
    mainLayout->addWidget(timesButton, 3, 4);
    mainLayout->addWidget(minusButton, 4, 4);
    mainLayout->addWidget(plusButton, 5, 4);

    mainLayout->addWidget(squareRootButton, 2, 5);
    mainLayout->addWidget(powerButton, 3, 5);
    mainLayout->addWidget(reciprocalButton, 4, 5);
    mainLayout->addWidget(equalButton, 5, 5);
    setLayout(mainLayout);

    setWindowTitle(tr("Calculator"));
}

레이아웃은 단일 ` QGridLayout`에 의해 처리됩니다. ` QLayout::setSizeConstraint()` 호출은 ` Calculator ` 위젯이 항상 최적의 크기( size hint)로 표시되도록 보장하여, 사용자가 계산기의 크기를 조정하지 못하도록 방지합니다. 크기 힌트는 자식 위젯의 크기와 ` size policy `에 의해 결정됩니다.

대부분의 자식 위젯은 그리드 레이아웃에서 하나의 셀만 차지합니다. 이러한 위젯의 경우, QGridLayout::addWidget()에 행과 열만 전달하면 됩니다. display, backspaceButton, clearButton 및 clearAllButton 위젯은 하나 이상의 열을 차지하므로, 이 경우 행 스팬과 열 스팬도 함께 전달해야 합니다.

void Calculator::digitClicked()
{
    Button *clickedButton = qobject_cast<Button *>(sender());
    int digitValue = clickedButton->text().toInt();
    if (display->text() == "0" && digitValue == 0.0)
        return;

    if (waitingForOperand) {
        display->clear();
        waitingForOperand = false;
    }
    display->setText(display->text() + QString::number(digitValue));
}

계산기의 숫자 버튼 중 하나를 누르면 해당 버튼의 clicked() 신호가 발생하며, 이는 digitClicked() 슬롯을 트리거합니다.

먼저, QObject::sender()를 사용하여 어떤 버튼이 신호를 보냈는지 확인합니다. 이 함수는 발신자를 QObject 포인터로 반환합니다. 발신자가 Button 객체임을 알고 있으므로, QObject 를 안전하게 형변환할 수 있습니다. C 스타일의 형변환이나 C++의 static_cast<>() 를 사용할 수도 있었겠지만, 방어적 프로그래밍 기법으로서 qobject_cast()를 사용합니다. 이 방법의 장점은 객체의 유형이 잘못되었을 경우 null 포인터가 반환된다는 점입니다. null 포인터로 인한 충돌은 안전하지 않은 형 변환으로 인한 충돌보다 진단하기가 훨씬 쉽습니다. 버튼을 확보한 후에는 QToolButton::text()를 사용하여 연산자를 추출합니다.

이 슬롯은 특히 두 가지 상황을 고려해야 합니다. display 에 "0"이 들어 있고 사용자가 ' 0 ' 버튼을 클릭한 경우, "00"을 표시하는 것은 부적절합니다. 또한 계산기가 새로운 피연산자를 기다리는 상태라면, 새로운 숫자는 그 새로운 피연산자의 첫 번째 자리가 됩니다. 이 경우, 이전 계산의 결과는 먼저 지워져야 합니다.

마지막으로, 디스플레이에 표시된 값 뒤에 새로운 숫자를 추가합니다.

void Calculator::unaryOperatorClicked()
{
    Button *clickedButton = qobject_cast<Button *>(sender());
    QString clickedOperator = clickedButton->text();
    double operand = display->text().toDouble();
    double result = 0.0;

    if (clickedOperator == tr("Sqrt")) {
        if (operand < 0.0) {
            abortOperation();
            return;
        }
        result = std::sqrt(operand);
    } else if (clickedOperator == tr("x\302\262")) {
        result = std::pow(operand, 2.0);
    } else if (clickedOperator == tr("1/x")) {
        if (operand == 0.0) {
            abortOperation();
            return;
        }
        result = 1.0 / operand;
    }
    display->setText(QString::number(result));
    waitingForOperand = true;
}

unaryOperatorClicked() 슬롯은 단항 연산자 버튼 중 하나가 클릭될 때마다 호출됩니다. 다시 한 번, QObject::sender()를 사용하여 클릭된 버튼에 대한 포인터를 가져옵니다. 버튼의 텍스트에서 연산자를 추출하여 clickedOperator 에 저장합니다. 피연산자는 display 에서 얻습니다.

그런 다음 연산을 수행합니다. Sqrt 가 음수에 적용되거나 1/x 가 0에 적용되는 경우, abortOperation() 를 호출합니다. 모든 과정이 정상적으로 진행되면, 연산 결과를 라인 편집창에 표시하고 waitingForOperand 를 true 로 설정합니다. 이를 통해 사용자가 새로운 숫자를 입력할 때, 해당 숫자가 현재 값에 추가되는 대신 새로운 피연산자로 간주되도록 보장합니다.

void Calculator::additiveOperatorClicked()
{
    Button *clickedButton = qobject_cast<Button *>(sender());
    if (!clickedButton)
      return;
    QString clickedOperator = clickedButton->text();
    double operand = display->text().toDouble();

사용자가 ‘ + ’ 또는 ‘ - ’ 버튼을 클릭하면 ‘ additiveOperatorClicked() ’ 슬롯이 호출됩니다.

클릭된 연산자에 대해 실제로 어떤 작업을 수행하기 전에, 먼저 처리되지 않은 작업이 있는지 확인해야 합니다. 곱셈 연산자는 덧셈 연산자보다 우선순위가 높으므로, 먼저 곱셈 연산자부터 처리합니다:

    if (!pendingMultiplicativeOperator.isEmpty()) {
        if (!calculate(operand, pendingMultiplicativeOperator)) {
            abortOperation();
            return;
        }
        display->setText(QString::number(factorSoFar));
        operand = factorSoFar;
        factorSoFar = 0.0;
        pendingMultiplicativeOperator.clear();
    }

만약 × 또는 ÷ 가 먼저 클릭되었고, 그 후 = 를 클릭하지 않은 경우, 디스플레이의 현재 값은 × 또는 ÷ 연산자의 우측 피연산자가 되며, 이제 마침내 연산을 수행하고 디스플레이를 업데이트할 수 있습니다.

    if (!pendingAdditiveOperator.isEmpty()) {
        if (!calculate(operand, pendingAdditiveOperator)) {
            abortOperation();
            return;
        }
        display->setText(QString::number(sumSoFar));
    } else {
        sumSoFar = operand;
    }

+ 이나 - 가 먼저 클릭된 경우, sumSoFar 는 왼쪽 피연산자이며, 디스플레이의 현재 값은 해당 연산자의 오른쪽 피연산자가 됩니다. 보류 중인 덧셈 연산자가 없는 경우, sumSoFar 는 단순히 디스플레이에 표시된 텍스트로 설정됩니다.

    pendingAdditiveOperator = clickedOperator;
    waitingForOperand = true;
}

마지막으로, 방금 클릭된 연산자를 처리할 수 있습니다. 아직 우측 피연산자가 없으므로, 클릭된 연산자를 pendingAdditiveOperator 변수에 저장합니다. 우측 피연산자가 확보되면 나중에 sumSoFar 을 좌측 피연산자로 사용하여 연산을 적용할 것입니다.

void Calculator::multiplicativeOperatorClicked()
{
    Button *clickedButton = qobject_cast<Button *>(sender());
    if (!clickedButton)
      return;
    QString clickedOperator = clickedButton->text();
    double operand = display->text().toDouble();

    if (!pendingMultiplicativeOperator.isEmpty()) {
        if (!calculate(operand, pendingMultiplicativeOperator)) {
            abortOperation();
            return;
        }
        display->setText(QString::number(factorSoFar));
    } else {
        factorSoFar = operand;
    }

    pendingMultiplicativeOperator = clickedOperator;
    waitingForOperand = true;
}

multiplicativeOperatorClicked() 슬롯은 additiveOperatorClicked() 슬롯과 유사합니다. 곱셈 연산자가 덧셈 연산자보다 우선순위가 높기 때문에, 여기서는 보류 중인 덧셈 연산자에 대해 걱정할 필요가 없습니다.

void Calculator::equalClicked()
{
    double operand = display->text().toDouble();

    if (!pendingMultiplicativeOperator.isEmpty()) {
        if (!calculate(operand, pendingMultiplicativeOperator)) {
            abortOperation();
            return;
        }
        operand = factorSoFar;
        factorSoFar = 0.0;
        pendingMultiplicativeOperator.clear();
    }
    if (!pendingAdditiveOperator.isEmpty()) {
        if (!calculate(operand, pendingAdditiveOperator)) {
            abortOperation();
            return;
        }
        pendingAdditiveOperator.clear();
    } else {
        sumSoFar = operand;
    }

    display->setText(QString::number(sumSoFar));
    sumSoFar = 0.0;
    waitingForOperand = true;
}

additiveOperatorClicked() 와 마찬가지로, 먼저 처리되지 않은 곱셈 연산자와 덧셈 연산자를 처리합니다. 그런 다음 sumSoFar 를 표시하고 변수를 0으로 재설정합니다. 변수를 0으로 재설정하는 것은 값이 두 번 계산되는 것을 방지하기 위해 필요합니다.

void Calculator::pointClicked()
{
    if (waitingForOperand)
        display->setText("0");
    if (!display->text().contains('.'))
        display->setText(display->text() + tr("."));
    waitingForOperand = false;
}

pointClicked() 슬롯은 display 의 내용에 소수점을 추가합니다.

void Calculator::changeSignClicked()
{
    QString text = display->text();
    double value = text.toDouble();

    if (value > 0.0) {
        text.prepend(tr("-"));
    } else if (value < 0.0) {
        text.remove(0, 1);
    }
    display->setText(text);
}

changeSignClicked() 슬롯은 display 의 값의 부호를 변경합니다. 현재 값이 양수이면 마이너스 기호를 앞에 붙이고, 현재 값이 음수이면 값의 첫 번째 문자(마이너스 기호)를 제거합니다.

void Calculator::backspaceClicked()
{
    if (waitingForOperand)
        return;

    QString text = display->text();
    text.chop(1);
    if (text.isEmpty()) {
        text = "0";
        waitingForOperand = true;
    }
    display->setText(text);
}

backspaceClicked() 는 표시된 값의 가장 오른쪽 문자를 제거합니다. 빈 문자열이 입력되면 "0"을 표시하고, waitingForOperand 를 true 로 설정합니다.

void Calculator::clear()
{
    if (waitingForOperand)
        return;

    display->setText("0");
    waitingForOperand = true;
}

clear() 슬롯은 현재 피연산자를 0으로 재설정합니다. 이는 Backspace 을 피연산자 전체가 지워질 때까지 여러 번 클릭하는 것과 동일합니다.

void Calculator::clearAll()
{
    sumSoFar = 0.0;
    factorSoFar = 0.0;
    pendingAdditiveOperator.clear();
    pendingMultiplicativeOperator.clear();
    display->setText("0");
    waitingForOperand = true;
}

clearAll() 슬롯은 계산기를 초기 상태로 재설정합니다.

void Calculator::clearMemory()
{
    sumInMemory = 0.0;
}

void Calculator::readMemory()
{
    display->setText(QString::number(sumInMemory));
    waitingForOperand = true;
}

void Calculator::setMemory()
{
    equalClicked();
    sumInMemory = display->text().toDouble();
}

void Calculator::addToMemory()
{
    equalClicked();
    sumInMemory += display->text().toDouble();
}

clearMemory() 슬롯은 메모리에 저장된 합계를 지우고, readMemory() 는 합계를 피연산자로 표시하며, setMemory() 는 메모리의 합계를 현재 합계로 대체하고, addToMemory() 는 메모리의 값에 현재 값을 더합니다. setMemory() 와 addToMemory() 의 경우, 먼저 equalClicked() 를 호출하여 sumSoFar 와 디스플레이의 값을 업데이트합니다.

template<typename PointerToMemberFunction>
Button *Calculator::createButton(const QString &text, const PointerToMemberFunction &member)
{
    Button *button = new Button(text);
    connect(button, &Button::clicked, this, member);
    return button;
}

비공개 함수 createButton() 는 생성자에서 호출되어 계산기 버튼을 생성합니다.

void Calculator::abortOperation()
{
    clearAll();
    display->setText(tr("####"));
}

계산이 실패할 때마다 비공개 함수 ` abortOperation() `가 호출됩니다. 이 함수는 계산기 상태를 초기화하고 "####"를 표시합니다.

bool Calculator::calculate(double rightOperand, const QString &pendingOperator)
{
    if (pendingOperator == tr("+")) {
        sumSoFar += rightOperand;
    } else if (pendingOperator == tr("-")) {
        sumSoFar -= rightOperand;
    } else if (pendingOperator == tr("\303\227")) {
        factorSoFar *= rightOperand;
    } else if (pendingOperator == tr("\303\267")) {
        if (rightOperand == 0.0)
            return false;
        factorSoFar /= rightOperand;
    }
    return true;
}

비공개 함수 ` calculate() `는 이항 연산을 수행합니다. 오른쪽 피연산자는 ` rightOperand`로 지정됩니다. 덧셈 연산자의 경우 왼쪽 피연산자는 ` sumSoFar`이며, 곱셈 연산자의 경우 왼쪽 피연산자는 ` factorSoFar`입니다. 이 함수는 0으로 나눗셈이 발생하면 ` false `를 반환합니다.

Button 클래스 정의

이제 ` Button ` 클래스를 살펴보겠습니다.

class Button : public QToolButton
{
    Q_OBJECT

public:
    explicit Button(const QString &text, QWidget *parent = nullptr);

    QSize sizeHint() const override;
};

Button 클래스에는 텍스트 레이블과 부모 위젯을 인수로 받는 편의 생성자가 있으며, QWidget::sizeHint() 메서드를 재구현하여 QToolButton 가 일반적으로 제공하는 것보다 텍스트 주위에 더 많은 공간을 확보합니다.

Button 클래스 구현

Button::Button(const QString &text, QWidget *parent)
    : QToolButton(parent)
{
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
    setText(text);
}

버튼의 모양은 레이아웃의 자식 위젯들의 크기와 size policy 을 통해 계산기 위젯의 레이아웃에 의해 결정됩니다. 생성자에서 setSizePolicy() 함수를 호출하면 버튼이 사용 가능한 모든 공간을 채우도록 가로로 확장됩니다. 기본적으로 QToolButton는 사용 가능한 공간을 채우도록 확장되지 않습니다. 이 호출이 없다면, 같은 열에 있는 서로 다른 버튼들의 너비가 제각각이 될 것입니다.

QSize Button::sizeHint() const
{
    QSize size = QToolButton::sizeHint();
    size.rheight() += 20;
    size.rwidth() = qMax(size.width(), size.height());
    return size;
}

sizeHint()에서는 대부분의 버튼에 잘 어울리는 크기를 반환하려고 합니다. 우리는 기본 클래스(QToolButton)의 크기 힌트를 재사용하지만 다음과 같은 방식으로 수정합니다:

  • 크기 힌트의 height 구성 요소에 20을 더합니다.
  • 크기 힌트의 width 구성 요소 값을 height 값 이상으로 설정합니다.

이렇게 하면 대부분의 글꼴에서 숫자 및 연산자 버튼이 정사각형 모양을 유지하면서, ‘ Backspace ’, ‘ Clear ’, ‘ Clear All ’ 버튼의 텍스트가 잘리지 않게 됩니다.

아래 스크린샷은 생성자에서 가로 크기 정책을 QSizePolicy::Expanding 로 설정하지 않았고, QWidget::sizeHint()를 재구현하지 않았을 경우 Calculator 위젯이 어떻게 표시되는지 보여줍니다.

버튼 배치가 어긋난 계산기

기본 크기 정책 및 크기 힌트가 적용된 계산기 예제

예제 프로젝트 @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.