import QtQuick 2.15 import QtQuick.Controls 2.15 Item { id: root anchors.fill: parent readonly property real a4Ratio: 1.4142 // высота = ширина * 1.4142 readonly property int pagesCount: 3 readonly property int pageSpacing: 12 // ГОСТ 2.104-2006 параметры рамок readonly property int outerMargin: 5 // отступ внешней рамки от края readonly property int frameSpacing: 20 // расстояние между рамками readonly property int innerFrameWidth: 1 // толщина внутренней рамки readonly property int outerFrameWidth: 2 // толщина внешней рамки // Преобразование ширины в условные единицы (мм) // A4: 210x297 мм, соотношение сторон 1:1.4142 readonly property real mmPerUnit: width / 210.0 // мм в одной единице QML readonly property real unitPerMm: 210.0 / width // единиц QML в одном мм // Удобные функции для работы с размерами в мм function mmToUnits(mm) { return mm * mmPerUnit } function unitsToMm(units) { return units * unitPerMm } Flickable { id: flick anchors.fill: parent clip: true boundsBehavior: Flickable.StopAtBounds interactive: true flickableDirection: Flickable.VerticalFlick contentWidth: width contentHeight: columnContent.height Column { id: columnContent width: flick.width spacing: root.pageSpacing // Явно задаем высоту, чтобы contentHeight корректно вычислялся height: implicitHeight // Верхний отступ, чтобы страница не прилипала к краю Item { width: 1; height: root.pageSpacing } // Первая страница - специальная, готовая для TableModel Rectangle { id: firstPage width: columnContent.width height: width * root.a4Ratio radius: 4 color: "#F7F2D0" border.color: "#D6CEAA" border.width: 1 // Внешняя рамка ГОСТ Rectangle { id: outerFrame1 anchors.fill: parent anchors.leftMargin: mmToUnits(20) anchors.topMargin: mmToUnits(5) anchors.bottomMargin: mmToUnits(5) anchors.rightMargin: mmToUnits(5) color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth } Rectangle{ id:leftFrame1 anchors.bottom: outerFrame1.bottom anchors.right: outerFrame1.left width: mmToUnits(5+7) height: mmToUnits(35+25+25+35+25) anchors.rightMargin: -outerFrame1.border.width color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth Rectangle{ id:field19Wrapper anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right height: mmToUnits(25) color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth Rectangle{ anchors.left: parent.left anchors.bottom: parent.bottom anchors.top: parent.top width:mmToUnits(5) color: "transparent" Text { anchors.centerIn: parent rotation: -90 text: qsTr("Инв. № подл") font.pixelSize: Math.min(parent.width * 0.8, parent.height * 0.3) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } Rectangle{ anchors.right: parent.right anchors.bottom: parent.bottom anchors.top: parent.top width:mmToUnits(7) color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth Text { anchors.centerIn: parent rotation: -90 text: qsTr("(19)") font.pixelSize: Math.min(parent.width * 0.8, parent.height * 0.3) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } } Rectangle{ id:field20Wrapper anchors.bottom: field19Wrapper.top anchors.left: parent.left anchors.right: parent.right height: mmToUnits(35)+ root.outerFrameWidth anchors.bottomMargin: - root.outerFrameWidth color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth Rectangle{ anchors.left: parent.left anchors.bottom: parent.bottom anchors.top: parent.top width:mmToUnits(5) color: "transparent" Text { anchors.centerIn: parent rotation: -90 text: qsTr("Подп. и дата") font.pixelSize: Math.min(parent.width * 0.8, parent.height * 0.3) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } Rectangle{ anchors.right: parent.right anchors.bottom: parent.bottom anchors.top: parent.top width:mmToUnits(7) color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth Text { anchors.centerIn: parent rotation: -90 text: qsTr("(20)") font.pixelSize: Math.min(parent.width * 0.8, parent.height * 0.3) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } } Rectangle{ id:field21Wrapper anchors.bottom: field20Wrapper.top anchors.left: parent.left anchors.right: parent.right height: mmToUnits(25)+ root.outerFrameWidth anchors.bottomMargin: - root.outerFrameWidth color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth Rectangle{ anchors.left: parent.left anchors.bottom: parent.bottom anchors.top: parent.top width:mmToUnits(5) color: "transparent" Text { anchors.centerIn: parent rotation: -90 text: qsTr("Взам. инв. №") font.pixelSize: Math.min(parent.width * 0.8, parent.height * 0.3) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } Rectangle{ anchors.right: parent.right anchors.bottom: parent.bottom anchors.top: parent.top width:mmToUnits(7) color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth Text { anchors.centerIn: parent rotation: -90 text: qsTr("(21)") font.pixelSize: Math.min(parent.width * 0.8, parent.height * 0.3) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } } Rectangle{ id:field22Wrapper anchors.bottom: field21Wrapper.top anchors.left: parent.left anchors.right: parent.right height: mmToUnits(25) + root.outerFrameWidth anchors.bottomMargin: - root.outerFrameWidth color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth Rectangle{ anchors.left: parent.left anchors.bottom: parent.bottom anchors.top: parent.top width:mmToUnits(5) color: "transparent" Text { anchors.centerIn: parent rotation: -90 text: qsTr("Инв. № дубл") font.pixelSize: Math.min(parent.width * 0.8, parent.height * 0.3) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } Rectangle{ anchors.right: parent.right anchors.bottom: parent.bottom anchors.top: parent.top width:mmToUnits(7) color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth Text { anchors.centerIn: parent rotation: -90 text: qsTr("(22)") font.pixelSize: Math.min(parent.width * 0.8, parent.height * 0.3) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } } Rectangle{ id:field23Wrapper anchors.bottom: field22Wrapper.top anchors.left: parent.left anchors.right: parent.right height: mmToUnits(35) +root.outerFrameWidth anchors.bottomMargin: -root.outerFrameWidth color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth Rectangle{ anchors.left: parent.left anchors.bottom: parent.bottom anchors.top: parent.top width:mmToUnits(5) color: "transparent" Text { anchors.centerIn: parent rotation: -90 text: qsTr("Подп. и дата") font.pixelSize: Math.min(parent.width * 0.8, parent.height * 0.3) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } Rectangle{ anchors.right: parent.right anchors.bottom: parent.bottom anchors.top: parent.top width:mmToUnits(7) color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth Text { anchors.centerIn: parent rotation: -90 text: qsTr("(23)") font.pixelSize: Math.min(parent.width * 0.8, parent.height * 0.3) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } } } Rectangle{ id:leftFrame1_2 anchors.top: outerFrame1.top anchors.right: outerFrame1.left width: mmToUnits(5+7) height: mmToUnits(120) anchors.rightMargin: -outerFrame1.border.width color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth Rectangle{ id:field24Wrapper anchors.bottom: leftFrame1_2.bottom anchors.left: parent.left anchors.right: parent.right height: mmToUnits(60) + root.outerFrameWidth // anchors.bottomMargin: - root.outerFrameWidth color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth Rectangle{ anchors.left: parent.left anchors.bottom: parent.bottom anchors.top: parent.top width:mmToUnits(5) color: "transparent" Text { anchors.centerIn: parent rotation: -90 text: qsTr("Справ. №") font.pixelSize: Math.min(parent.width * 0.8, parent.height * 0.3) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } Rectangle{ anchors.right: parent.right anchors.bottom: parent.bottom anchors.top: parent.top width:mmToUnits(7) color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth Text { anchors.centerIn: parent rotation: -90 text: qsTr("(24)") font.pixelSize: Math.min(parent.width * 0.8, parent.height * 0.3) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } } Rectangle{ id:field25Wrapper anchors.bottom: field24Wrapper.top anchors.left: parent.left anchors.right: parent.right height: mmToUnits(60) //+root.outerFrameWidth anchors.bottomMargin: -root.outerFrameWidth color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth Rectangle{ anchors.left: parent.left anchors.bottom: parent.bottom anchors.top: parent.top width:mmToUnits(5) color: "transparent" Text { anchors.centerIn: parent rotation: -90 text: qsTr("Перв. примен") font.pixelSize: Math.min(parent.width * 0.8, parent.height * 0.3) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } Rectangle{ anchors.right: parent.right anchors.bottom: parent.bottom anchors.top: parent.top width:mmToUnits(7) color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth Text { anchors.centerIn: parent rotation: -90 text: qsTr("(25)") font.pixelSize: Math.min(parent.width * 0.8, parent.height * 0.3) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } } } Rectangle{ id:innerBottomFrame1 anchors.bottom: outerFrame1.bottom anchors.right: outerFrame1.right width: mmToUnits(185) height: mmToUnits(55) color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth Rectangle{ id:firstColumn1 anchors.left: parent.left anchors.top:parent.top anchors.bottom: parent.bottom width: mmToUnits(17) +2*root.outerFrameWidth// border color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth } Rectangle{ id:secondColumn1 anchors.left: firstColumn1.right anchors.top:parent.top anchors.bottom: parent.bottom anchors.leftMargin: -root.outerFrameWidth width: mmToUnits(23)+2*root.outerFrameWidth // border color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth } Rectangle{ id:thirdColumn1 anchors.left: secondColumn1.right anchors.top:parent.top anchors.bottom: parent.bottom width: mmToUnits(15)+2*root.outerFrameWidth // border anchors.leftMargin: -root.outerFrameWidth color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth } Rectangle{ id:forthColumn1 anchors.left: thirdColumn1.right anchors.top:parent.top anchors.bottom: parent.bottom width: mmToUnits(10)+2*root.outerFrameWidth // border color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth anchors.leftMargin: -root.outerFrameWidth } Rectangle{ id:fifthColumn1 anchors.left: forthColumn1.right anchors.top:parent.top anchors.bottom: parent.bottom anchors.right: parent.right color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth anchors.leftMargin: -root.outerFrameWidth Rectangle{ id:field2Wrapper anchors.top: parent.top anchors.left:parent.left anchors.right: parent.right height: mmToUnits(15) color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth Text { anchors.fill:parent text: qsTr("(2)") } } Rectangle{ id:field21_4Wrapper anchors.top: field2Wrapper.bottom anchors.left:parent.left anchors.right: parent.right anchors.topMargin: -root.outerFrameWidth height: mmToUnits(25) + 2* root.outerFrameWidth color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth } Rectangle{ id:field3__Wrapper anchors.top: field21_4Wrapper.bottom anchors.left:parent.left anchors.right: parent.right anchors.topMargin: -root.outerFrameWidth height: mmToUnits(15) color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth } } } // Внутренняя рамка ГОСТ // Rectangle { // id: innerFrame1 // anchors.fill: parent // anchors.margins: root.outerMargin + root.frameSpacing // color: "transparent" // border.color: "#000000" // border.width: root.innerFrameWidth // } // Основная надпись (левая нижняя часть) // Rectangle { // id: mainInscription1 // anchors.left: innerFrame1.left // anchors.bottom: innerFrame1.bottom // width: mmToUnits(185) // 185 мм // height: mmToUnits(55) // 55 мм // color: "transparent" // border.color: "#000000" // border.width: 1 // // Графы основной надписи // Grid { // anchors.fill: parent // columns: 8 // rows: 11 // // Инв. номер // Rectangle { // width: mmToUnits(25); height: mmToUnits(5) // color: "transparent" // border.color: "#000000" // border.width: 0.5 // Text { // anchors.centerIn: parent // text: "Инв. №" // font.pixelSize: 8 // color: "#000000" // } // } // // Подпись и дата // Rectangle { // width: mmToUnits(25); height: mmToUnits(5) // color: "transparent" // border.color: "#000000" // border.width: 0.5 // Text { // anchors.centerIn: parent // text: "Подп." // font.pixelSize: 8 // color: "#000000" // } // } // // Лист // Rectangle { // width: mmToUnits(25); height: mmToUnits(5) // color: "transparent" // border.color: "#000000" // border.width: 0.5 // Text { // anchors.centerIn: parent // text: "Лист" // font.pixelSize: 8 // color: "#000000" // } // } // // Листов // Rectangle { // width: mmToUnits(25); height: mmToUnits(5) // color: "transparent" // border.color: "#000000" // border.width: 0.5 // Text { // anchors.centerIn: parent // text: "Листов" // font.pixelSize: 8 // color: "#000000" // } // } // // Масштаб // Rectangle { // width: mmToUnits(25); height: mmToUnits(5) // color: "transparent" // border.color: "#000000" // border.width: 0.5 // Text { // anchors.centerIn: parent // text: "Масштаб" // font.pixelSize: 8 // color: "#000000" // } // } // // Масса // Rectangle { // width: mmToUnits(25); height: mmToUnits(5) // color: "transparent" // border.color: "#000000" // border.width: 0.5 // Text { // anchors.centerIn: parent // text: "Масса" // font.pixelSize: 8 // color: "#000000" // } // } // // Разработал // Rectangle { // width: mmToUnits(25); height: mmToUnits(5) // color: "transparent" // border.color: "#000000" // border.width: 0.5 // Text { // anchors.centerIn: parent // text: "Разраб." // font.pixelSize: 8 // color: "#000000" // } // } // // Проверил // Rectangle { // width: mmToUnits(25); height: mmToUnits(5) // color: "transparent" // border.color: "#000000" // border.width: 0.5 // Text { // anchors.centerIn: parent // text: "Пров." // font.pixelSize: 8 // color: "#000000" // } // } // } // } // Заголовок первой страницы // Здесь будет TableModel } // Остальные страницы Repeater { model: root.pagesCount - 1 delegate: Rectangle { id: pageDelegate width: columnContent.width height: width * root.a4Ratio radius: 4 color: "#F7F2D0" border.color: "#D6CEAA" border.width: 1 // Внешняя рамка ГОСТ Rectangle { id: outerFrame anchors.fill: parent anchors.margins: root.outerMargin color: "transparent" border.color: "#000000" border.width: root.outerFrameWidth } // Внутренняя рамка ГОСТ Rectangle { id: innerFrame anchors.fill: parent anchors.margins: root.outerMargin + root.frameSpacing color: "transparent" border.color: "#000000" border.width: root.innerFrameWidth } // Основная надпись (левая нижняя часть) Rectangle { id: mainInscription anchors.left: innerFrame.left anchors.bottom: innerFrame.bottom width: mmToUnits(185) // 185 мм height: mmToUnits(55) // 55 мм color: "transparent" border.color: "#000000" border.width: 1 // Графы основной надписи Grid { anchors.fill: parent columns: 8 rows: 11 // Инв. номер Rectangle { width: mmToUnits(25); height: mmToUnits(5) color: "transparent" border.color: "#000000" border.width: 0.5 Text { anchors.centerIn: parent text: "Инв. №" font.pixelSize: 8 color: "#000000" } } // Подпись и дата Rectangle { width: mmToUnits(25); height: mmToUnits(5) color: "transparent" border.color: "#000000" border.width: 0.5 Text { anchors.centerIn: parent text: "Подп." font.pixelSize: 8 color: "#000000" } } // Лист Rectangle { width: mmToUnits(25); height: mmToUnits(5) color: "transparent" border.color: "#000000" border.width: 0.5 Text { anchors.centerIn: parent text: "Лист" font.pixelSize: 8 color: "#000000" } } // Листов Rectangle { width: mmToUnits(25); height: mmToUnits(5) color: "transparent" border.color: "#000000" border.width: 0.5 Text { anchors.centerIn: parent text: "Листов" font.pixelSize: 8 color: "#000000" } } // Масштаб Rectangle { width: mmToUnits(25); height: mmToUnits(5) color: "transparent" border.color: "#000000" border.width: 0.5 Text { anchors.centerIn: parent text: "Масштаб" font.pixelSize: 8 color: "#000000" } } // Масса Rectangle { width: mmToUnits(25); height: mmToUnits(5) color: "transparent" border.color: "#000000" border.width: 0.5 Text { anchors.centerIn: parent text: "Масса" font.pixelSize: 8 color: "#000000" } } // Разработал Rectangle { width: mmToUnits(25); height: mmToUnits(5) color: "transparent" border.color: "#000000" border.width: 0.5 Text { anchors.centerIn: parent text: "Разраб." font.pixelSize: 8 color: "#000000" } } // Проверил Rectangle { width: mmToUnits(25); height: mmToUnits(5) color: "transparent" border.color: "#000000" border.width: 0.5 Text { anchors.centerIn: parent text: "Пров." font.pixelSize: 8 color: "#000000" } } } } Text { anchors.centerIn: parent text: "Страница " + (index + 2) color: "#2c2c2c" font.pixelSize: 16 } } } // Нижний отступ Item { width: 1; height: root.pageSpacing } } // Прокрутка колесом мыши (актуально для QQuickWidget) MouseArea { anchors.fill: parent hoverEnabled: true acceptedButtons: Qt.NoButton propagateComposedEvents: true onWheel: { const maxY = Math.max(0, flick.contentHeight - flick.height) // angleDelta.y положителен при прокрутке вверх const step = wheel.angleDelta.y flick.contentY = Math.min(maxY, Math.max(0, flick.contentY - step)) wheel.accepted = true } } } // Вертикальная полоса прокрутки ScrollBar { id: vbar anchors.right: parent.right anchors.top: parent.top anchors.bottom: parent.bottom orientation: Qt.Vertical policy: ScrollBar.AsNeeded width: 14 z: 1000 // Настроим видимость и позиционирование относительно содержимого Flickable size: Math.min(1, flick.height / Math.max(1, flick.contentHeight)) position: flick.contentY / Math.max(1, (flick.contentHeight - flick.height)) onPositionChanged: { const maxY = Math.max(0, flick.contentHeight - flick.height) flick.contentY = position * maxY } } }