Programming/qt2026. 1. 16. 14:19

'Programming > qt' 카테고리의 다른 글

qt quick websocket  (0) 2026.01.14
qt qml loader  (0) 2026.01.14
qstackedwidget, qstackedlayout  (0) 2026.01.13
qt quick 예제 calqlatr 코드분석  (0) 2026.01.13
qt qml view  (0) 2026.01.13
Posted by 구차니
Programming/C Win32 MFC2026. 1. 16. 10:44

비슷한걸 만들어 보려고 하는데 영 안되는데 신기한 옵션을 찾아서 글 써봄

의도적으로 heap을 넘기는 코드를 작성하고 free() 시에 정말 segmentation fault 가 뜨나 해보는데

$ cat t2.c 
#include <stdio.h>
#include <stdlib.h>

void main()
{
int *arr = NULL;
arr = (int*)malloc(10 * sizeof(int));
int idx = 0;
for(idx = 0; idx < 10000; idx++)
arr[idx] = idx;

printf("before\n");
fflush(stdout);

free(arr);

printf("after\n");
fflush(stdout);
}

 

아쉽게도 free가 아니라 arr[idx] 에서 범위를 넘어서 에러가 발생함

$ gcc t2.c -g
$ ./a.out 
malloc(): corrupted top size
중지됨 (코어 덤프됨)

 

fsanitize 라는 플래그를 주면 좀더 잡아 준다는데 컴파일 타임이 아니라 런타임에 작동한다.

해당 플래그를 추가하면 빌드된 용량이 증가한다.

$ gcc t2.c -g -fsanitize=address
$ ls -al
합계 40
-rwxrwxr-x  1 minimonk minimonk 23536  1월 16 10:33 a.out
-rw-rw-r--  1 minimonk minimonk   271  1월 16 10:30 t2.c

$ gcc t2.c -g
$ ls -al
합계 36
-rwxrwxr-x  1 minimonk minimonk 18704  1월 16 10:35 a.out
-rw-rw-r--  1 minimonk minimonk   271  1월 16 10:30 t2.c

[링크 :https://k0n9.tistory.com/entry/AddressSanitizer]

[링크 : https://stackoverflow.com/questions/58262749/how-to-use-gcc-with-fsanitize-address]

 

실행해서 터트리면 아래와 같이 먼가 나오는데, 엄청 컬러풀하게 터진다.

눈에 들어오는건 summay 항목의 heap-buffer-overflow

특이한게 배열 loop 돌다 터지는게 아니라 다 돌고 나서 free 가려다가 터진다. 신기하네

$ gcc t2.c -g -fsanitize=address
$ ./a.out 
=================================================================
==2713847==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x504000000038 at pc 0x609d568b42e0 bp 0x7ffdaa34e820 sp 0x7ffdaa34e810
WRITE of size 4 at 0x504000000038 thread T0
    #0 0x609d568b42df in main /home/minimonk/work/src/malloc/t2.c:9
    #1 0x7cc2e8429d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #2 0x7cc2e8429e3f in __libc_start_main_impl ../csu/libc-start.c:392
    #3 0x609d568b41a4 in _start (/home/minimonk/work/src/malloc/a.out+0x11a4)

0x504000000038 is located 0 bytes to the right of 40-byte region [0x504000000010,0x504000000038)
allocated by thread T0 here:
    #0 0x7cc2e88b4887 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
    #1 0x609d568b4286 in main /home/minimonk/work/src/malloc/t2.c:7
    #2 0x7cc2e8429d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/minimonk/work/src/malloc/t2.c:9 in main
Shadow bytes around the buggy address:
  0x0a087fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0a087fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0a087fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0a087fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0a087fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0a087fff8000: fa fa 00 00 00 00 00[fa]fa fa fa fa fa fa fa fa
  0x0a087fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0a087fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0a087fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0a087fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0a087fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==2713847==ABORTING

 

idx 값을 보면 10000번 돌았는데

printf 하려고 하면 바로 malloc(): corrupted top size 하면서 터진다.

$ gdb ./a.out 
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04.2) 12.1
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...
(gdb) l
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 void main()
5 {
6 int *arr = NULL;
7 arr = (int*)malloc(10 * sizeof(int));
8 int idx = 0;
9 for(idx = 0; idx < 10000; idx++)
10 arr[idx] = idx;
(gdb) l 11
6 int *arr = NULL;
7 arr = (int*)malloc(10 * sizeof(int));
8 int idx = 0;
9 for(idx = 0; idx < 10000; idx++)
10 arr[idx] = idx;
11
12 printf("before\n");
13 fflush(stdout);
14
15 free(arr);
(gdb) b 12
Breakpoint 1 at 0x1201: file t2.c, line 12.
(gdb) r
Starting program: /home/minimonk/work/src/malloc/a.out 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main () at t2.c:12
12 printf("before\n");
(gdb) print idx
$1 = 10000
(gdb) n
malloc(): corrupted top size

Program received signal SIGABRT, Aborted.
__pthread_kill_implementation (no_tid=0, signo=6, threadid=140737353705280) at ./nptl/pthread_kill.c:44
44 ./nptl/pthread_kill.c: 그런 파일이나 디렉터리가 없습니다.

 

그래서 printf / fflush 주석처리하고 free를 바로 브레이크 포인트 잡아서 해도 동일하게 

루프 종료되면서 바로 에러가 나는 것 같기도...

15 free(arr);
(gdb) c
Continuing.
malloc(): corrupted top size

Program received signal SIGABRT, Aborted.
__pthread_kill_implementation (no_tid=0, signo=6, threadid=140737353705280) at ./nptl/pthread_kill.c:44
44 ./nptl/pthread_kill.c: 그런 파일이나 디렉터리가 없습니다.
(gdb) 

 

'Programming > C Win32 MFC' 카테고리의 다른 글

float 자릿수 제한  (0) 2025.10.11
free(): invalid next size (normal)  (0) 2023.12.18
c에서 cpp 함수 불러오기  (0) 2023.01.04
MSB / LSB 변환  (0) 2022.08.29
kore - c restful api server  (1) 2022.07.07
Posted by 구차니
Programming/qt2026. 1. 14. 12:38

socket은 좀더 찾아 봐야 할 것 같은데

내부통신이 아닌 외부장치와의 통신은 qt quick / qml 에서 어떻게 구현되는지 궁금해짐

 

qmlwebsocketserver main.qml qmlwebsocketclient main.qml
// Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

import QtQuick
import QtWebSockets

Rectangle {
    width: 360
    height: 360

    function appendMessage(message) {
        messageBox.text += "\n" + message
    }

    WebSocketServer {
        id: server
        listen: true
        onClientConnected: function(webSocket) {
            webSocket.onTextMessageReceived.connect(function(message) {
                appendMessage(qsTr("Server received message: %1").arg(message));
                webSocket.sendTextMessage(qsTr("Hello Client!"));
            });
        }
        onErrorStringChanged: {
            appendMessage(qsTr("Server error: %1").arg(errorString));
        }
    }

    WebSocket {
        id: socket
        url: server.url
        onTextMessageReceived: function(message) {
            appendMessage(qsTr("Client received message: %1").arg(message));
        }
        onStatusChanged: {
            if (socket.status == WebSocket.Error) {
                appendMessage(qsTr("Client error: %1").arg(socket.errorString));
            } else if (socket.status == WebSocket.Closed) {
                appendMessage(qsTr("Client socket closed."));
            }
        }
    }

    Timer {
        interval: 100
        running: true
        onTriggered: {
            socket.active = true;
        }
    }

    Text {
        id: messageBox
        text: qsTr("Click to send a message!")
        anchors.fill: parent

        MouseArea {
            anchors.fill: parent
            onClicked: {
                socket.sendTextMessage(qsTr("Hello Server!"));
            }
        }
    }
}
// Copyright (C) 2016 Kurt Pattyn <pattyn.kurt@gmail.com>.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
import QtWebSockets

Rectangle {
    width: 640
    height: 360

    WebSocket {
        id: socket
        url: "ws://ws.ifelse.io"
        onTextMessageReceived: function(message) {
            messageBox.text = messageBox.text + "\nReceived message: " + message
        }
        onStatusChanged: if (socket.status == WebSocket.Error) {
                             console.log("Error: " + socket.errorString)
                         } else if (socket.status == WebSocket.Open) {
                             socket.sendTextMessage("Hello World")
                         } else if (socket.status == WebSocket.Closed) {
                             messageBox.text += "\nSocket closed"
                         }
        active: false
    }

    WebSocket {
        id: secureWebSocket
        url: "wss://ws.ifelse.io"
        onTextMessageReceived: function(message) {
            messageBox.text = messageBox.text + "\nReceived secure message: " + message
        }
        onStatusChanged: if (secureWebSocket.status == WebSocket.Error) {
                             console.log("Error: " + secureWebSocket.errorString)
                         } else if (secureWebSocket.status == WebSocket.Open) {
                             secureWebSocket.sendTextMessage("Hello Secure World")
                         } else if (secureWebSocket.status == WebSocket.Closed) {
                             messageBox.text += "\nSecure socket closed"
                         }
        active: false
    }
    Text {
        id: messageBox
        text: socket.status == WebSocket.Open ? qsTr("Sending...") : qsTr("Welcome!")
        anchors.centerIn: parent
    }

    MouseArea {
        anchors.fill: parent
        onClicked: {
            socket.active = !socket.active
            secureWebSocket.active =  !secureWebSocket.active;
            //Qt.quit();
        }
    }
}

 

 다른 예제

[링크 : https://makersweb.net/qt/22792]

'Programming > qt' 카테고리의 다른 글

qt qml 와 c++ 상호연동  (0) 2026.01.16
qt qml loader  (0) 2026.01.14
qstackedwidget, qstackedlayout  (0) 2026.01.13
qt quick 예제 calqlatr 코드분석  (0) 2026.01.13
qt qml view  (0) 2026.01.13
Posted by 구차니
Programming/qt2026. 1. 14. 10:54

로더라는 말은 몇번 봤는데 예제는 이제 찾아봄.

구현 자체는 무지 쉬워보이는데 라이프 사이클이라던가 좀 봐야할 듯.

import QtQuick

Item {
    width: 200; height: 200

    Loader { id: pageLoader }

    MouseArea {
        anchors.fill: parent
        onClicked: pageLoader.source = "Page1.qml"
    }
}

[링크 : https://doc.qt.io/qt-6/ko/qml-qtquick-loader.html]

[링크 : https://blog.naver.com/ekthatkxkd/221722032058]

[링크 : https://studiodoc.tistory.com/176]

'Programming > qt' 카테고리의 다른 글

qt qml 와 c++ 상호연동  (0) 2026.01.16
qt quick websocket  (0) 2026.01.14
qstackedwidget, qstackedlayout  (0) 2026.01.13
qt quick 예제 calqlatr 코드분석  (0) 2026.01.13
qt qml view  (0) 2026.01.13
Posted by 구차니
Programming/qt2026. 1. 13. 15:46

dialog 띄우고 show, hide 하는것도 방법이지만

layout 에다가 widget을 추가하고 layout을 stack 해서 새 창을 띄울 것들을 새로운 stack에 넣어서 하는 것도 방법이고

아니면 위젯을 스택해서 쓰는것도 방법일 듯 한데

구조적으로는 stackedlayout에 widget을 넣어 운영하는게 좀 더 맞는 듯?

 

QStackedLayout QStackedWidget
import sys, os

# Qt 바인딩을 PySide6 우선 사용하고, 실패 시 PyQt6 사용
qt_modules = None

# PySide6을 먼저 시도
try:
    from PySide6.QtWidgets import (
        QApplication, QWidget,
        QStackedLayout, QVBoxLayout,
        QLabel,
        QComboBox, 
    )
    from PySide6.QtGui import QPixmap
    qt_modules = 'PySide6'
except ImportError:
    # 실패 시 PyQt6 시도
    try:
        from PyQt6.QtWidgets import (
            QApplication, QWidget,
            QStackedLayout, QVBoxLayout,
            QLabel,
            QComboBox, 
        )
        from PyQt6.QtGui import QPixmap
        qt_modules = 'PyQt6'
    except ImportError:
        # 둘 다 실패하면 메시지 출력 후 종료
        print("There is no Qt Binding for Python.")
        sys.exit(1)

# 사용된 Qt 바인딩 이름 출력
print(f"Using {qt_modules} binding.")

# ------------------------------------

# 메인 윈도우 클래스 정의
class MW(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        # 윈도우 타이틀 설정
        self.setWindowTitle("Ex Input Widgets")
        # 메인 위젯 및 레이아웃 구성
        self.setup_main_wnd()
        # 윈도우 표시
        self.show()

    def setup_main_wnd(self):
        # 현재 파일의 절대 경로 기준 디렉토리 경로 얻기
        fpath = os.path.dirname(
            os.path.abspath(__file__)
        )

        # 콤보박스에 표시될 페이지 이름들
        pages = ['faith', 'hope', 'love']

        # 각 페이지에 해당하는 이미지 파일 경로 리스트
        self.imgs = [
            os.path.join(fpath, 'img','faith.png'),
            os.path.join(fpath, 'img','hope.png'),
            os.path.join(fpath, 'img','love.png')
        ]

        # 콤보박스 생성 및 항목 추가
        combo_box = QComboBox()
        combo_box.addItems(pages)
        # 콤보박스 항목이 선택되면 change_page 함수 실행
        combo_box.activated.connect(self.change_page)

        # QStackedLayout 생성 (여러 페이지를 겹쳐서 보관, 하나만 보여줌)
        self.stacked_lm = QStackedLayout()

        # 페이지 수만큼 QLabel 생성 후 QStackedLayout에 추가
        for idx, c in enumerate(pages):
            label = self.setup_page(idx)  # QLabel을 생성하고 이미지 설정
            self.stacked_lm.addWidget(label)  # 스택에 추가

        # 수직 박스 레이아웃 생성
        v_box_lm = QVBoxLayout()
        v_box_lm.addWidget(combo_box)         # 콤보박스를 위에 추가
        # 스택 레이아웃을 아래에 추가
        # v_box_lm.addLayout(self.stacked_lm)  # 이 한줄로 아래 3개라인을 대체 가능.
        tmp_c = QWidget()
        tmp_c.setLayout(self.stacked_lm)
        v_box_lm.addWidget(tmp_c)

        # 최종 레이아웃을 윈도우에 설정
        self.setLayout(v_box_lm)

    # 페이지용 QLabel 설정 함수
    def setup_page(self, page_num):
        label = QLabel()
        pixmap = QPixmap(self.imgs[page_num])     # 해당 이미지 불러오기
        label.setPixmap(pixmap)                   # QLabel에 이미지 설정
        label.setScaledContents(True)             # QLabel 크기에 맞게 이미지 자동 조절
        return label

    # 콤보박스에서 선택된 인덱스에 해당하는 페이지를 보여줌
    def change_page(self, idx):
        self.stacked_lm.setCurrentIndex(idx)

# ------------------------------------

# 프로그램 진입점
if __name__ == "__main__":
    print(os.path.realpath(__file__))  # 현재 실행 중인 파일 경로 출력
    app = QApplication(sys.argv)       # QApplication 인스턴스 생성
    main_wnd = MW()                         # 메인 윈도우 생성
    sys.exit(app.exec())               # 이벤트 루프 실행

import sys, os

# Qt 바인딩을 PySide6 우선, PyQt6는 백업용
qt_modules = None

try:
    from PySide6.QtWidgets import (
        QApplication, QWidget, QLabel,
        QVBoxLayout, QComboBox, QStackedWidget
    )
    from PySide6.QtGui import QPixmap
    qt_modules = 'PySide6'
except ImportError:
    try:
        from PyQt6.QtWidgets import (
            QApplication, QWidget, QLabel,
            QVBoxLayout, QComboBox, QStackedWidget
        )
        from PyQt6.QtGui import QPixmap
        qt_modules = 'PyQt6'
    except ImportError:
        print("There is no Qt Binding for Python.")
        sys.exit(1)

print(f"Using {qt_modules} binding.")

# ------------------------------------

class MW(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle("Ex: QStackedWidget with ComboBox")
        self.setup_main_wnd()
        self.show()

    def setup_main_wnd(self):
        # 현재 스크립트 경로를 기준으로 이미지 파일 위치 설정
        fpath = os.path.dirname(os.path.abspath(__file__))

        # 페이지 이름과 이미지 경로 정의
        pages = ['faith', 'hope', 'love']
        self.imgs = [
            os.path.join(fpath, 'img/faith.png'),
            os.path.join(fpath, 'img/hope.png'),
            os.path.join(fpath, 'img/love.png')
        ]

        # 콤보박스 생성 및 페이지 이름 추가
        combo_box = QComboBox()
        combo_box.addItems(pages)
        combo_box.activated.connect(self.change_page)

        # QStackedWidget 생성
        self.stack_widget = QStackedWidget()

        # 각 페이지에 해당하는 QLabel + 이미지 추가
        for idx in range(len(pages)):
            label = QLabel()
            pixmap = QPixmap(self.imgs[idx])
            label.setPixmap(pixmap)
            label.setScaledContents(True)  # 이미지가 QLabel에 맞게 리사이즈됨
            self.stack_widget.addWidget(label)

        # 수직 레이아웃 구성: 콤보박스 위, 이미지 아래
        layout = QVBoxLayout()
        layout.addWidget(combo_box)
        layout.addWidget(self.stack_widget)

        self.setLayout(layout)

    # 콤보박스 인덱스 선택 시 보여줄 페이지 변경
    def change_page(self, idx):
        self.stack_widget.setCurrentIndex(idx)

# ------------------------------------

if __name__ == "__main__":
    print(os.path.realpath(__file__))
    app = QApplication(sys.argv)
    main_wnd = MW()
    sys.exit(app.exec())

[링크 : https://wikidocs.net/185879]

qstackedwidget

[링크 : https://wikidocs.net/162838]

[링크 : https://doc.qt.io/qt-6/qwidget.html]

[링크 : https://doc.qt.io/qt-6/qstackedwidget.html]

[링크 : https://qt-dev.com/board.php?board=qnaboard&page=4&category=1&command=body&no=758]

[링크 : https://hobbylife.tistory.com/entry/PySide6-QStackedWidget-완전-정복-–-클릭-이벤트와-사용법]

 

qstackedlayout

[링크 : https://m.blog.naver.com/raffiner/222027119916]

[링크 : https://doc.qt.io/qt-6/qstackedlayout.html]

'Programming > qt' 카테고리의 다른 글

qt quick websocket  (0) 2026.01.14
qt qml loader  (0) 2026.01.14
qt quick 예제 calqlatr 코드분석  (0) 2026.01.13
qt qml view  (0) 2026.01.13
qt quick 이미지 클릭  (0) 2026.01.12
Posted by 구차니
Programming/qt2026. 1. 13. 14:39

qt quick 으로 작성된 계산기 어플 소스 분석

 

실행하면 평범한 계산기가 뜬다.

 

가로로 길게 늘리면 공학계산기로 바뀐다.

 

프로젝트는 아래와 같이 구성되어 있고

 

main.cpp

언제나 그렇듯(?) main.cpp 는 조촐하고 별 내용이 없다.

// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickStyle>

int main(int argc, char *argv[])
{
    QCoreApplication::setOrganizationName("QtProject");
    QCoreApplication::setApplicationName("Calqlatr");

    QGuiApplication app(argc, argv);

    QQuickStyle::setStyle("Basic");

    QQmlApplicationEngine engine;
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
            &app, []() { QCoreApplication::exit(-1); },
            Qt::QueuedConnection);
    engine.loadFromModule("demos.calqlatr", "Main");

    return app.exec();
}

 

Main.qml

전체 모양을 그리는 녀석인데, design 에서 보면 아래처럼 보인다.

 

다만 qt designer의 버그인지 ApplicationState 의 id: state 구문이 에러가 나는데

위지윅 에디터에서 보려면 해당 라인을 주석처리 하면 된다. (물론 실행하면 작동안하게 되는 버그 발생)

 

 

column, row Layout 으로 배치를 어떻게 하는것 같고

Keys.onPressed: function (event) {} 를 통해서 키 입력시 state에 추가하는 식으로 작동하게 된다.

// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

import QtQuick
import QtQuick.Layouts

Window {
    visible: true
    width: 320
    height: 480
    minimumWidth: Math.max(numberPad.portraitModeWidth, display.minWidth) + root.margin * 2
    minimumHeight: display.minHeight + numberPad.height + root.margin * 3
    color: root.backgroundColor

    Item {
        id: root
        anchors.fill: parent

        anchors.topMargin: parent.SafeArea.margins.top
        anchors.leftMargin: parent.SafeArea.margins.left
        anchors.rightMargin: parent.SafeArea.margins.right
        anchors.bottomMargin: parent.SafeArea.margins.bottom

        readonly property int margin: 18
        readonly property color backgroundColor: "#222222"
        readonly property int minLandscapeModeWidth: numberPad.landscapeModeWidth
                                                     + display.minWidth + margin * 3

        property bool isPortraitMode: root.width < root.minLandscapeModeWidth

        ApplicationState {
            id: state
            display: display
        }

        Display {
            id: display
            readonly property int minWidth: 210
            readonly property int minHeight: 60

            Layout.minimumWidth: minWidth
            Layout.fillWidth: true
            Layout.fillHeight: true
            Layout.margins: root.margin

            // remove the margin on the side that the numberPad is on, to prevent a double margin
            Layout.bottomMargin: root.isPortraitMode ? 0 : root.margin
            Layout.rightMargin: root.isPortraitMode ? root.margin : 0
        }

        NumberPad {
            id: numberPad
            Layout.margins: root.margin

            isPortraitMode: root.isPortraitMode
            state: state
        }

        // define the responsive layouts
        ColumnLayout {
            id: portraitMode
            anchors.fill: parent
            visible: root.isPortraitMode

            LayoutItemProxy {
                target: display
                Layout.minimumHeight: display.minHeight
            }
            LayoutItemProxy {
                target: numberPad
                Layout.alignment: Qt.AlignHCenter
            }
        }

        RowLayout {
            id: landscapeMode
            anchors.fill: parent
            visible: !root.isPortraitMode

            LayoutItemProxy {
                target: display
            }
            LayoutItemProxy {
                target: numberPad
                Layout.alignment: Qt.AlignVCenter
            }
        }

        Keys.onPressed: function (event) {
            switch (event.key) {
                case Qt.Key_0: state.digitPressed("0"); break;
                case Qt.Key_1: state.digitPressed("1"); break;
                case Qt.Key_2: state.digitPressed("2"); break;
                case Qt.Key_3: state.digitPressed("3"); break;
                case Qt.Key_4: state.digitPressed("4"); break;
                case Qt.Key_5: state.digitPressed("5"); break;
                case Qt.Key_6: state.digitPressed("6"); break;
                case Qt.Key_7: state.digitPressed("7"); break;
                case Qt.Key_8: state.digitPressed("8"); break;
                case Qt.Key_9: state.digitPressed("9"); break;
                case Qt.Key_E: state.digitPressed("e"); break;
                case Qt.Key_P: state.digitPressed("π"); break;
                case Qt.Key_Plus: state.operatorPressed("+"); break;
                case Qt.Key_Minus: state.operatorPressed("-"); break;
                case Qt.Key_Asterisk: state.operatorPressed("×"); break;
                case Qt.Key_Slash: state.operatorPressed("÷"); break;
                case Qt.Key_Enter:
                case Qt.Key_Return: state.operatorPressed("="); break;
                case Qt.Key_Comma:
                case Qt.Key_Period: state.digitPressed("."); break;
                case Qt.Key_Backspace: state.operatorPressed("bs"); break;
            }
        }
    }
}

 

ApplicationState.qml

말로는 qml  인데 design에서 보여지는 요소는 존재하지 않고

main.qml 에서 호출되는 operatorPressed() 나 digitPressed()와 같은 함수가 존재한다.

특이한건 import as 인데 js를 불러서 CalcEngine 으로 사용하는 부분 정도?

그 와중에 Display는 display.qml 에서 끌려오는건가?

// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

import QtQml
import "calculator.js" as CalcEngine

QtObject {
    required property Display display

    function operatorPressed(operator) {
        CalcEngine.operatorPressed(operator, display);
    }
    function digitPressed(digit) {
        CalcEngine.digitPressed(digit, display);
    }
    function isButtonDisabled(op) {
        return CalcEngine.isOperationDisabled(op, display);
    }
}

 

calculator.js

평범한(?) js로 작성된 코드가 존재한다.

// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

let accumulator = 0
let pendingOperator = ""
let lastButton = ""
let digits = ""

function isOperationDisabled(op, display) {
    if (digits !== "" && lastButton !== "=" && (op === "π" || op === "e"))
        return true
    if (digits === "" && !((op >= "0" && op <= "9") || op === "π" || op === "e" || op === "AC"))
        return true
    if (op === "bs" && (display.isOperandEmpty() || !((lastButton >= "0" && lastButton <= "9")
                                                      || lastButton === "π" || lastButton === "e" || lastButton === ".")))
        return true
    if (op === '=' && pendingOperator.length != 1)
        return true
    if (op === "." && digits.search(/\./) != -1)
        return true
    if (op === "√" &&  digits.search(/-/) != -1)
        return true
    if (op === "AC" && display.isDisplayEmpty())
        return true

    return false
}

function digitPressed(op, display) {
    if (isOperationDisabled(op, display))
        return
    if (lastButton === "π" || lastButton === "e")
        return
    // handle mathematical constants
    if (op === "π") {
        lastButton = op
        digits = Math.PI.toPrecision(display.maxDigits - 1).toString()
        display.appendDigit(digits)
        return
    }
    if (op === "e") {
        lastButton = op
        digits = Math.E.toPrecision(display.maxDigits - 1).toString()
        display.appendDigit(digits)
        return
    }

    // append a digit to another digit or decimal point
    if (lastButton.toString().length === 1 && ((lastButton >= "0" && lastButton <= "9") || lastButton === ".") ) {
        if (digits.length >= display.maxDigits)
            return
        digits = digits + op.toString()
        display.appendDigit(op.toString())
    // else just write a single digit to display
    } else {
        digits = op.toString()
        display.appendDigit(digits)
    }
    lastButton = op
}

function operatorPressed(op, display) {
    if (isOperationDisabled(op, display))
        return

    if (op === "±") {
        digits = Number(digits.valueOf() * -1).toString()
        display.setDigit(display.displayNumber(Number(digits)))
        return
    }

    if (op === "bs") {
        digits = digits.slice(0, -1)
        if (digits === "-")
            digits = ""
        display.backspace()
        return
    }

    lastButton = op

    if (pendingOperator === "+") {
        digits = (Number(accumulator) + Number(digits.valueOf())).toString()
    } else if (pendingOperator === "−") {
        digits = (Number(accumulator) - Number(digits.valueOf())).toString()
    } else if (pendingOperator === "×") {
        digits = (Number(accumulator) * Number(digits.valueOf())).toString()
    } else if (pendingOperator === "÷") {
        digits = (Number(accumulator) / Number(digits.valueOf())).toString()
    }


    if (op === "+" || op === "−" || op === "×" || op === "÷") {
        pendingOperator = op
        accumulator = digits.valueOf()
        digits = ""
        display.displayOperator(pendingOperator)
        return
    }

    accumulator = 0
    pendingOperator = ""

    if (op === "=") {
        display.newLine("=", Number(digits))
    }

    if (op === "√") {
        digits = (Math.sqrt(digits.valueOf())).toString()
        display.newLine("√", Number(digits))
    } else if (op === "⅟x") {
        digits = (1 / digits.valueOf()).toString()
        display.newLine("⅟x", Number(digits))
    } else if (op === "x²") {
        digits = (digits.valueOf() * digits.valueOf()).toString()
        display.newLine("x²", Number(digits))
    } else if (op === "x³") {
        digits = (digits.valueOf() * digits.valueOf() * digits.valueOf()).toString()
        display.newLine("x³", Number(digits))
    } else if (op === "|x|") {
        digits = (Math.abs(digits.valueOf())).toString()
        display.newLine("|x|", Number(digits))
    } else if (op === "⌊x⌋") {
        digits = (Math.floor(digits.valueOf())).toString()
        display.newLine("⌊x⌋", Number(digits))
    } else if (op === "sin") {
        digits = Number(Math.sin(digits.valueOf())).toString()
        display.newLine("sin", Number(digits))
    } else if (op === "cos") {
        digits = Number(Math.cos(digits.valueOf())).toString()
        display.newLine("cos", Number(digits))
    } else if (op === "tan") {
        digits = Number(Math.tan(digits.valueOf())).toString()
        display.newLine("tan", Number(digits))
    } else if (op === "log") {
        digits = Number(Math.log10(digits.valueOf())).toString()
        display.newLine("log", Number(digits))
    } else if (op === "ln") {
        digits = Number(Math.log(digits.valueOf())).toString()
        display.newLine("ln", Number(digits))
    }

    if (op === "AC") {
        display.allClear()
        accumulator = 0
        lastButton = ""
        digits = ""
        pendingOperator = ""
    }
}

 

Display.qml

design 상에서는 별 내용이 없어 보이지만

 

코드에서는 라인별로 추가하는 등 제법 ui를 건드리는 작동을 많이 한다.

// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

pragma ComponentBehavior: Bound

import QtQuick

Item {
    id: display
    property int fontSize: 22
    readonly property int maxDigits: Math.min((width / fontSize) + 1, 9)
    readonly property color backgroundColor: "#262626"
    readonly property color qtGreenColor: "#2CDE85"
    property string displayedOperand: ""
    readonly property string errorString: qsTr("ERROR")
    readonly property bool isError: displayedOperand === errorString
    property bool enteringDigits: false

    function displayOperator(operator) {
        calculationsListView.model.append({
                                              "operator": operator,
                                              "operand": ""
                                          });
        enteringDigits = true;
        calculationsListView.positionViewAtEnd();
    }

    function newLine(operator, operand) {
        displayedOperand = displayNumber(operand);
        calculationsListView.model.append({
                                              "operator": operator,
                                              "operand": displayedOperand
                                          });
        enteringDigits = false;
        calculationsListView.positionViewAtEnd();
    }

    function appendDigit(digit) {
        if (!enteringDigits)
            calculationsListView.model.append({
                                                  "operator": "",
                                                  "operand": ""
                                              });
        const i = calculationsListView.model.count - 1;
        calculationsListView.model.get(i).operand = calculationsListView.model.get(i).operand
                + digit;
        enteringDigits = true;
        calculationsListView.positionViewAtEnd();
    }

    function setDigit(digit) {
        const i = calculationsListView.model.count - 1;
        calculationsListView.model.get(i).operand = digit;
        calculationsListView.positionViewAtEnd();
    }

    function backspace() {
        const i = calculationsListView.model.count - 1;
        if (i >= 0) {
            let operand = calculationsListView.model.get(i).operand.toString().slice(0, -1);
            if (operand === "-")
                operand = "";
            calculationsListView.model.get(i).operand = operand;
            return;
        }
        return;
    }

    function isOperandEmpty() {
        const i = calculationsListView.model.count - 1;
        return i >= 0 ? calculationsListView.model.get(i).operand === "" : true;
    }

    function isDisplayEmpty() {
        const i = calculationsListView.model.count - 1;
        return i == -1 ? true : (i == 0 ? calculationsListView.model.get(0).operand === "" : false);
    }

    function clear() {
        displayedOperand = "";
        if (enteringDigits) {
            const i = calculationsListView.model.count - 1;
            if (i >= 0)
                calculationsListView.model.remove(i);
            enteringDigits = false;
        }
    }

    function allClear() {
        display.clear();
        calculationsListView.model.clear();
        enteringDigits = false;
    }

    // Returns a string representation of a number that fits in
    // display.maxDigits characters, trying to keep as much precision
    // as possible. If the number cannot be displayed, returns an
    // error string.
    function displayNumber(num) {
        if (typeof (num) !== "number")
            return errorString;

        // deal with the absolute
        const abs = Math.abs(num);

        if (abs.toString().length <= maxDigits) {
            return isFinite(num) ? num.toString() : errorString;
        }

        if (abs < 1) {
            // check if abs < 0.00001, if true, use exponential form
            // if it isn't true, we can round the number without losing
            // too much precision
            if (Math.floor(abs * 100000) === 0) {
                const expVal = num.toExponential(maxDigits - 6).toString();
                if (expVal.length <= maxDigits + 1)
                    return expVal;
            } else {
                // the first two digits are zero and .
                return num.toFixed(maxDigits - 2);
            }
        } else {
            // if the integer part of num is greater than maxDigits characters, use exp form
            const intAbs = Math.floor(abs);
            if (intAbs.toString().length <= maxDigits)
                return parseFloat(num.toPrecision(maxDigits - 1)).toString();

            const expVal = num.toExponential(maxDigits - 6).toString();
            if (expVal.length <= maxDigits + 1)
                return expVal;
        }
        return errorString;
    }

    Item {
        anchors.fill: parent

        Rectangle {
            anchors.fill: parent
            radius: 8
            color: display.backgroundColor

            ListView {
                idcalculationsListView
                x: 5
                y: 10
                width: parent.width
                height: parent.height - 2 * y
                clip: true
                delegate: Item {
                    height: display.fontSize * 1.1
                    width: calculationsListView.width

                    required property string operator
                    required property string operand

                    Text {
                        x: 6
                        font.pixelSize: display.fontSize
                        color: display.qtGreenColor
                        text: parent.operator
                        Accessible.name: parent.operator
                    }
                    Text {
                        font.pixelSize: display.fontSize
                        anchors.right: parent.right
                        anchors.rightMargin: 16
                        text: parent.operand
                        Accessible.name: parent.operand
                        color: "white"
                    }
                }
                model: ListModel {}
                onHeightChanged: positionViewAtEnd()
            }
        }
    }
}

 

 

Numpad.qml

계산기의 버튼 부분인것 같은데 rectangle 안에 Rowlayout  안에 GridLayout이 있는데 그래서 그런가 이상하게 보여지는 느낌.

 

그나저나 제곱이나 sin tan 같은 과학계산기도 넣으려다가 흔적만 남은건가?

// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

pragma ComponentBehavior: Bound

import QtQuick
import QtQuick.Layouts

Item {
    id: controller

    required property bool isPortraitMode
    required property ApplicationState state

    readonly property color qtGreenColor: "#2CDE85"
    readonly property color backspaceRedColor: "#DE2C2C"
    readonly property int spacing: 5

    property int portraitModeWidth: mainGrid.width
    property int landscapeModeWidth: scientificGrid.width + mainGrid.width

    implicitWidth: isPortraitMode ? portraitModeWidth : landscapeModeWidth
    implicitHeight: mainGrid.height

    function updateDimmed() {
        for (let i = 0; i < mainGrid.children.length; i++) {
            mainGrid.children[i].dimmed = state.isButtonDisabled(mainGrid.children[i].text);
        }
        for (let j = 0; j < scientificGrid.children.length; j++) {
            scientificGrid.children[j].dimmed = state.isButtonDisabled(
                        scientificGrid.children[j].text);
        }
    }

    component DigitButton: CalculatorButton {
        onClicked: {
            controller.state.digitPressed(text);
            controller.updateDimmed();
        }
    }

    component OperatorButton: CalculatorButton {
        dimmable: true
        implicitWidth: 48
        textColor: controller.qtGreenColor

        onClicked: {
            controller.state.operatorPressed(text);
            controller.updateDimmed();
        }
    }

    Component.onCompleted: updateDimmed()

    Rectangle {
        id: numberPad
        anchors.fill: parent
        radius: 8
        color: "transparent"

        RowLayout {
            spacing: controller.spacing

            GridLayout {
                id: scientificGrid
                columns: 3
                columnSpacing: controller.spacing
                rowSpacing: controller.spacing
                visible: !controller.isPortraitMode

                OperatorButton {
                    text: "x²"
                    Accessible.name: "x squared"
                }
                OperatorButton {
                    text: "⅟x"
                    Accessible.name: "one over x"
                }
                OperatorButton { text: "√" }
                OperatorButton {
                    text: "x³"
                    Accessible.name: "x cubed"
                }
                OperatorButton {
                    text: "sin"
                    Accessible.name: "sine"
                }
                OperatorButton {
                    text: "|x|"
                    Accessible.name: "absolute value"
                }
                OperatorButton { text: "log" }
                OperatorButton {
                    text: "cos"
                    Accessible.name: "cosine"
                }
                DigitButton {
                    text: "e"
                    dimmable: true
                    implicitWidth: 48
                }
                OperatorButton { text: "ln" }
                OperatorButton { text: "tan" }
                DigitButton {
                    text: "π"
                    dimmable: true
                    implicitWidth: 48
                }
            }

            GridLayout {
                id: mainGrid
                columns: 5
                columnSpacing: controller.spacing
                rowSpacing: controller.spacing

                BackspaceButton {
                    onClicked: {
                        controller.state.operatorPressed(this.text);
                        controller.updateDimmed();
                    }
                }

                DigitButton { text: "7" }
                DigitButton { text: "8" }
                DigitButton { text: "9" }
                OperatorButton {
                    text: "÷"
                    implicitWidth: 38
                }

                OperatorButton {
                    text: "AC"
                    textColor: controller.backspaceRedColor
                    accentColor: controller.backspaceRedColor
                }
                DigitButton { text: "4" }
                DigitButton { text: "5" }
                DigitButton { text: "6" }
                OperatorButton {
                    text: "×"
                    implicitWidth: 38
                }

                OperatorButton {
                    text: "="
                    implicitHeight: 81
                    Layout.rowSpan: 2
                }
                DigitButton { text: "1" }
                DigitButton { text: "2" }
                DigitButton { text: "3" }
                OperatorButton {
                    text: "−"
                    implicitWidth: 38
                }

                OperatorButton {
                    text: "±"
                    implicitWidth: 38
                }
                DigitButton { text: "0" }
                DigitButton {
                    text: "."
                    dimmable: true
                }
                OperatorButton {
                    text: "+"
                    implicitWidth: 38
                }
            }
        } // RowLayout
    }
}

 

 

BackspaceButton.qml

numpad 에서 호출되는 버튼. 그 외에는 크게 눈에 띄진 않네

// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

import QtQuick
import QtQuick.Controls

RoundButton {
    id: button
    implicitWidth: 48
    implicitHeight: 38
    radius: buttonRadius
    icon.source: getIcon()
    icon.width: 38
    icon.height: 38
    icon.color: getIconColor()
    // include this text property as the calculator engine
    // differentiates buttons through text. The text is never drawn.
    text: "bs"
    Accessible.name: "backspace"

    property bool dimmable: true
    property bool dimmed: false
    readonly property color backgroundColor: "#222222"
    readonly property color borderColor: "#A9A9A9"
    readonly property color backspaceRedColor: "#DE2C2C"
    readonly property int buttonRadius: 8

    function getBackgroundColor() {
        if (button.dimmable && button.dimmed)
            return backgroundColor;
        if (button.pressed)
            return backspaceRedColor;
        return backgroundColor;
    }

    function getBorderColor() {
        if (button.dimmable && button.dimmed)
            return borderColor;
        if (button.pressed || button.hovered)
            return backspaceRedColor;
        return borderColor;
    }

    function getIconColor() {
        if (button.dimmable && button.dimmed)
            return Qt.darker(backspaceRedColor);
        if (button.pressed)
            return backgroundColor;
        return backspaceRedColor;
    }

    function getIcon() {
        if (button.dimmable && button.dimmed)
            return "images/backspace.svg";
        if (button.pressed)
            return "images/backspace_fill.svg";
        return "images/backspace.svg";
    }

    background: Rectangle {
        radius: button.buttonRadius
        color: button.getBackgroundColor()
        border.color: button.getBorderColor()
    }
}

 

CalculatorButton.qml

numpad 에서 호출되는 버튼. 그 외에는 크게 눈에 띄진 않네 2

// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

import QtQuick
import QtQuick.Controls

RoundButton {
    id: button
    implicitWidth: 38
    implicitHeight: 38
    radius: buttonRadius

    property bool dimmable: false
    property bool dimmed: false
    readonly property int fontSize: 22
    readonly property int buttonRadius: 8
    property color textColor: "#FFFFFF"
    property color accentColor: "#2CDE85"
    readonly property color backgroundColor: "#222222"
    readonly property color borderColor: "#A9A9A9"

    function getBackgroundColor() {
        if (button.dimmable && button.dimmed)
            return backgroundColor;
        if (button.pressed)
            return accentColor;
        return backgroundColor;
    }

    function getBorderColor() {
        if (button.dimmable && button.dimmed)
            return borderColor;
        if (button.pressed || button.hovered)
            return accentColor;
        return borderColor;
    }

    function getTextColor() {
        if (button.dimmable && button.dimmed)
            return Qt.darker(textColor);
        if (button.pressed)
            return backgroundColor;
        if (button.hovered)
            return accentColor;
        return textColor;
    }

    background: Rectangle {
        radius: button.buttonRadius
        color: button.getBackgroundColor()
        border.color: button.getBorderColor()
    }

    contentItem: Text {
        text: button.text
        font.pixelSize: button.fontSize
        horizontalAlignment: Text.AlignHCenter
        verticalAlignment: Text.AlignVCenter
        color: button.getTextColor()
        Behavior on color {
            ColorAnimation {
                duration: 120
                easing.type: Easing.OutElastic
            }
        }
    }
}

'Programming > qt' 카테고리의 다른 글

qt qml loader  (0) 2026.01.14
qstackedwidget, qstackedlayout  (0) 2026.01.13
qt qml view  (0) 2026.01.13
qt quick 이미지 클릭  (0) 2026.01.12
qt creator 18.0.1 design 활성화 하기  (0) 2026.01.09
Posted by 구차니
Programming/qt2026. 1. 13. 10:59

전체적인 레이아웃 잡는데에는 split view 나 stack view 나 tabview 정도가 적절해 보이는군.

 

ScrollView Provides a scrolling view within another Item
SplitView Lays out items with a draggable splitter between each item
StackView Provides a stack-based navigation model
TabView A control that allows the user to select one of multiple stacked items
TableView Provides a list view with scroll bars, styling and header sections
TreeView Provides a tree view with scroll bars, styling and header sections

[링크 : https://doc.qt.io/archives/qt-5.15/qtquick-controls-qmlmodule.html]

[링크 : https://doc.qt.io/archives/qt-5.15/qml-qtquick-controls-stackview.html]

 

onclicked 이벤트에서 stackview.push 함수를 이용하여 qml을 넣어주면 끝인듯. 편하겠네

넣는건 push 빼는건 pop. 직관적이네~

onClicked: {
             stackView.push(Qt.resolvedUrl("qrc:/screen2.qml"))//다음 화면을 출력하기 위해 stack에 화면을 쌓는 코드
             //stack에 메인화면 두번째화면 세번째 화면이 쌓이게 된다.
        }

onClicked: {
            stackView.pop();//이전화면을 호출하기위해 stack의 제일 위에 화면을 밖으로 빼주어 첫화면을 보여준다.
        }

[링크 : https://youonlyliveonce1.tistory.com/16]

 

qt creator 에서 찾아보니 swipe view라는게 추가되어 보이고, 다른 tab 이나 split view가 안보인다.

Posted by 구차니
Programming/qt2026. 1. 12. 17:58

2026.01.13

다시보다 보니 기본 컴포넌트에 mouse area 라는 것이 있다.

이미지 하나 띄우고 마우스 영역을 지정하고 원하는 크기로 조절하면

과거 html 에서 이미지 맵 하듯 가능해진다.

 

mouse area에서 area는 활성화 되는데 hover는 활성화 되어있지 않아서 체크를 해줘야 하고

체크를 해주면 의도한 대로 작동되게 된다.

----

 

qt quick 으로 생성해서 이미지를 넣고 사진을 띄우는것 까진 성공!(프로젝트 외부 디렉토리에 이미지는 안됨)

그래서 이미지를 클릭하면 무언가 하려고 하는데

connections 라던가 event list 에서 무언가 쓸만해 보이는게 뜨지 않는다.

 

 

그래서 우클릭 후 Add Mouse Area를 해주면

 

 

 image가 아니라 mouseArea로 잡히고

 

평범하게 보던 mouse 클릭 이벤트 들을 사용할 수 있게 된다.

 

확인필요

[링크 : https://studiodoc.tistory.com/171]

'Programming > qt' 카테고리의 다른 글

qt quick 예제 calqlatr 코드분석  (0) 2026.01.13
qt qml view  (0) 2026.01.13
qt creator 18.0.1 design 활성화 하기  (0) 2026.01.09
qt 변수 초기화 문법, cpp 초기화 리스트  (0) 2021.12.08
qt5 fb reset  (0) 2021.02.23
Posted by 구차니
Programming/qt2026. 1. 9. 18:18

메뉴 help - About plugins

 

Qt Quick 에서 QT Quick Designer (deprecated) 를 체크하고 재시작 하면 된다.

 

 

그냥 곱게(?) Design studio 띄우는 법은 없나?

 

[링크 : https://dev-optimist.tistory.com/44]

[링크 : https://makersweb.net/qt/13535]

'Programming > qt' 카테고리의 다른 글

qt qml view  (0) 2026.01.13
qt quick 이미지 클릭  (0) 2026.01.12
qt 변수 초기화 문법, cpp 초기화 리스트  (0) 2021.12.08
qt5 fb reset  (0) 2021.02.23
qt framebuffer에 출력하기  (0) 2021.02.09
Posted by 구차니
Programming/golang2025. 11. 24. 19:04

golang 에서 커밋 해시를 바이너리에 넣는 방법을 찾아보는 중

 

아래 방법은 링커에서 변수에 넣는것 같은데 이것도 쓸만해 보이긴 한데..

go build -ldflags "-X my/package/config.Version=1.0.0"

[링크 : https://www.reddit.com/r/golang/comments/rhpbvo/what_kind_of_things_have_you_ran_with_gogenerate/?tl=ko]

 

go version은 좀더 상세한 자료가 들어가는것 같은데 좀더 나은 접근 방법이 될 듯?

go version
The go command now embeds version control information in binaries. It includes the currently checked-out revision, commit time, and a flag indicating whether edited or untracked files are present. Version control information is embedded if the go command is invoked in a directory within a Git, Mercurial, Fossil, or Bazaar repository, and the main package and its containing main module are in the same repository. This information may be omitted using the flag -buildvcs=false.

Additionally, the go command embeds information about the build, including build and tool tags (set with -tags), compiler, assembler, and linker flags (like -gcflags), whether cgo was enabled, and if it was, the values of the cgo environment variables (like CGO_CFLAGS). Both VCS and build information may be read together with module information using go version -m file or runtime/debug.ReadBuildInfo (for the currently running binary) or the new debug/buildinfo package.

The underlying data format of the embedded build information can change with new go releases, so an older version of go may not handle the build information produced with a newer version of go. To read the version information from a binary built with go 1.18, use the go version command and the debug/buildinfo package from go 1.18+.

[링크 : https://tip.golang.org/doc/go1.18#go-command]

'Programming > golang' 카테고리의 다른 글

golang 정적웹 파일 포함하기  (0) 2025.11.24
go vet (golang 정적분석)  (0) 2025.10.02
golang 윈도우 서비스 프로그램 작성하기  (0) 2025.02.18
golang tcp socket timeout 주기(listen, read)  (0) 2024.04.08
golang reflect  (0) 2024.02.20
Posted by 구차니