Implement a scrollview with cocos2d-x 3.6 - c++

wondering if anyone knows how to implement a scroll view in cocos2d-x 3.6 (C++). All the tutorials I have found are for earlier cocos2d-x versions.
Thanks
I added my code below, I can get the grey scrollview box to show but it cant be scrolled and the buttons don't appear on it:
header files: "CocosGUI.h" and "cocos-ext.h"
//add scroll view
Size scollFrameSize = Size(visibleSize.width, visibleSize.height/4);
auto scrollView = cocos2d::ui::ScrollView::create();
scrollView->setContentSize(scollFrameSize);
scrollView->setBackGroundColorType(cocos2d::ui::Layout::BackGroundColorType::SOLID);
scrollView->setBackGroundColor(Color3B(200, 200, 200));
scrollView->setPosition(Point(0, visibleSize.height/1.5));
scrollView->setDirection(cocos2d::ui::ScrollView::Direction::HORIZONTAL);
scrollView->setBounceEnabled(true);
scrollView->setTouchEnabled(true);
auto containerSize = Size(scollFrameSize.width*2, scollFrameSize.height*2);
scrollView->setInnerContainerSize(containerSize);
this->addChild(scrollView);
auto button1 = cocos2d::ui::Button::create();
button1->setColor(Color3B(250, 200, 50));
button1->setTouchEnabled(true);
button1->setContentSize(Size(100, 100));
button1->setPosition(Point(containerSize.width / 4, containerSize.height / 2));
scrollView->addChild(button1);
auto button2 = cocos2d::ui::Button::create();
button2->setColor(Color3B(250, 200, 50));
button1->setContentSize(Size(100, 100));
button2->setTouchEnabled(true);
button2->setPosition(Point(containerSize.width / 8, containerSize.height / 2));
scrollView->addChild(button2);

I figured it out, It was scrolling but I added my buttons wrong. For anyone who is interested add a button like this
auto button1 = ui::Button::create();
button1->setTouchEnabled(true);
button1->ignoreContentAdaptWithSize(false);
button1->setContentSize(Size(100, 100));
button1->loadTextures("pic1.png", "pic2.png");
button1->setPosition(Point(containerSize.width / 8, containerSize.height / 2));
scrollView->addChild(button1);

Size scroll_size = Director::getInstance()->getWinSize();
Size container_size = Size(scroll_size.width * 2, scroll_size.height);
Layer* container = Layer::create();
container->setContentSize(container_size);
ScrollView* scroll = ScrollView::create(scroll_size, container);
mScroll->setDelegate(this);
mScroll->setDirection(ScrollView::Direction::HORIZONTAL);
1.size of container should be larger than size of scrollview
2.add child to container, not scrollview
3.implement ScrollViewDelegate

Related

Why is my QGraphicsLine in the wrong place

I want to draw a line to connect two circles (QGraphicsEllipseItem), but I find that I don't get the desired result with this way of writing.
//they have been initialized to the correct place
QGraphicsEllipseItem* nodeu;
QGraphicsEllipseItem* nodev;
this->addLine(nodeu->x(), nodeu->y(), nodev->x(), nodev->y());
The result of executing these codes is that only two circles appear, but no lines appear.
like this
My rough inference is the problem of coordinate transformation, but I just can't solve it.
thank you!
you should first add one QGraphicsView in your UI or :
QGraphicsView *graphicsView;
QGridLayout *gridLayout;
gridLayout = new QGridLayout(centralwidget);
gridLayout->setSpacing(0);
gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
graphicsView = new QGraphicsView(centralwidget);
graphicsView->setObjectName(QString::fromUtf8("graphicsView"));
gridLayout->addWidget(graphicsView, 0, 0, 1, 1);
then :
QGraphicsScene *_scene = new QGraphicsScene(this);
ui->graphicsView->setScene(_scene);
ui->graphicsView->setRenderHints(QPainter::Antialiasing);
QGraphicsEllipseItem *nodeu = new QGraphicsEllipseItem;
nodeu->setRect(20, 10, 20, 20);
_scene->addItem(nodeu);
QGraphicsEllipseItem *nodev = new QGraphicsEllipseItem;
nodev->setRect(80, 60, 20, 20);
_scene->addItem(nodev);
QGraphicsLineItem *_lineItem = new QGraphicsLineItem;
_lineItem->setLine(nodeu->rect().x() + nodeu->rect().width() / 2.0, nodeu->rect().y() + nodeu->rect().height() / 2.0,
nodev->rect().x() + nodev->rect().width() / 2.0, nodev->rect().y() + nodev->rect().height() / 2.0);
_scene->addItem(_lineItem);
this is the output:

Rendering in Vertical Layout fails to occur

I am trying to create a timeline app for visualization of certain time-sensitive requirements information and have begun experimentation with Qt since I am new to it. The problem I am having is that the rendered object will show up if I render it just basically on the main background, but when I tried to add the TimeLine objects to the vertical layout I have on my UI they refuse to render.
Here is my main window code for creating the objects:
void MainWindow::drawTimelines()
{
for(int i=0; i <= 3; i++)
{
TimeLine *tl = new TimeLine(this, this);
// ui->verticalLayout->addWidget(tl, 0, Qt::AlignLeft);
tl->lower();
QPoint * dest = new QPoint(this->width() - (this->width() / 12), i * this->height() / 4 + this->height() / 4);
QPoint * src = new QPoint(this->width() / 12, i * this->height() / 4 + this->height() / 4);
// tl->setGeometry(0, 0, this->width(), 100);
tl->setGeometry(src->x(), src->y(), this->width(), 100);
tl->updateGeometry();
QPoint *startPt = new QPoint(src->x(), 50);
QPoint *endPt = new QPoint(dest->x(), 50);
// QPoint *src = new QPoint(this->width() /8, 50);
// QPoint *dest = new QPoint(this->width() - (this->width() / 8), 50);
tl->setSrcPt(startPt);
tl->setDestPt(endPt);
tl->setNumSegments(3);
timeLineList.push_back(tl);
timeLineList.at(i)->show();
}
update();
}
Here is the maint function present in the TimeLine object itself:
void TimeLine::paintEvent(QPaintEvent * event)
{
QRectF frame(QPointF(sourcePoint->x(), sourcePoint->y()), geometry().size());
QPainter painter(this);
painter.setPen(QPen(Qt::FlatCap));
painter.drawRoundedRect(frame, 10.0, 10.0);
int translateAmount = sourcePoint->y() - window->getPainterY();
painter.translate(0, translateAmount);
// window->setPainterY(translateAmount);
painter.drawLine(sourcePoint->x(), 25, destPoint->x(), 25);
for(int i = 0; i <= numSegments; i++){
int xPoint = ((destPoint->x() - sourcePoint->x()) * i / numSegments) + sourcePoint->x();
int yPoint = 25;
painter.drawLine(xPoint, yPoint + 20, xPoint, yPoint - 20);
}
QWidget::paintEvent(event);
}
For reference, the verticalLayout is meant to have one
The TimeLines (and bounded rect boxes) do not render when I have the
// ui->verticalLayout->addWidget(tl, 0, Qt::AlignLeft);
uncommented. As you can see from a bunch of the other commented lines, I have tried numerous other things to try and render these TimeLines. I have tried:
changing reference points of the geometry to be (0,0) for the new segment of the vertical layout
changing the size of the geometry
both translating and not translating the painter
changing line thickness, type of line, etc.
even tried rendering something else simple in the vertical layout
The part that confuses me is that even the bounded rect made based on the geometry of the TimeLine frame gets cut off on the side and top of the timeline (it only shows top left corner and the top and left side-lines) even when rendered on the normal screen.

How can I resize QMessageBox?

I have a QMessageBox which I'd like it to be bigger. It's a simple QMessageBox with two standard buttons, Ok and Cancel. The problem is that it is very small for my application's purposes. Code shows like this:
QMessageBox msg;
msg.setText("Whatever");
msg.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msg.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
int ret = msg.exec();
switch (ret) {
case QMessageBox::Ok:
ui->textEdit->clear();
break;
case QMessageBox::Cancel:
break;}
I tried several ways to increase the size:
msg.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
msg.setSizePolicy(QSizePolicy::Maximum,QSizePolicy::Maximum);
msg.setFixedHeight(600);
msg.setFixedWidth(600);
I even cleared and rebuilt, and it compiles everything but nothing take effect...
Do you have any idea on how to set QMessageBox size "by hand"? Thanks.
You can edit the css of the label:
msg.setStyleSheet("QLabel{min-width: 700px;}");
You can similarly edit the css of the buttons to add a margin or make them bigger.
For example:
msg.setStyleSheet("QLabel{min-width:500 px; font-size: 24px;} QPushButton{ width:250px; font-size: 18px; }");
There is also a trick mentioned:
QSpacerItem* horizontalSpacer = new QSpacerItem(800, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
QGridLayout* layout = (QGridLayout*)msg.layout();
layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount());
But this doesn't seem to work for everyone.
coyotte508's answer caused my layout to be horribly off center and at different widths it was cut off. In searching around further I found this thread which explains a better solution.
In essence the layout of a messagebox is a grid, so you can add a SpacerItem to it to control the width. Here's the c++ code sample from that link:
QMessageBox msgBox;
QSpacerItem* horizontalSpacer = new QSpacerItem(500, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
msgBox.setText( "SomText" );
QGridLayout* layout = (QGridLayout*)msgBox.layout();
layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount());
msgBox.exec();
You can subclass QMessageBox and reimplement resize event handler as following:
void MyMessageBox::resizeEvent(QResizeEvent *Event)
{
QMessageBox::resizeEvent(Event);
this->setFixedWidth(myFixedWidth);
this->setFixedHeight(myFixedHeight);
}
I wanted my QMessageBox width to adapt in proportion to the length of the text content with a certain amount of buffer to avoid line wrap. After surveying numerous forums and threads including this one, I came up with:
int x_offset = (2.0 * MainWindow::geometry().x());
int y_offset = (0.5 * MainWindow::geometry().y());
msgBox.setText(vers_msg.data());
QSpacerItem* horizontalSpacer = new QSpacerItem
(8 * vers_msg.size(), 0,
QSizePolicy::Minimum, QSizePolicy::Expanding);
QGridLayout* layout = (QGridLayout*)msgBox.layout();
layout->addItem(horizontalSpacer, layout->rowCount(),
0, 1, layout->columnCount());
msgBox.setGeometry(
MainWindow::geometry().x() + x_offset,
MainWindow::geometry().y() + y_offset,
msgBox.geometry().width(),
msgBox.geometry().height());
Adjust the hard numbers in x_offset, y_offset and horizontalSpacer to suit your situation. I was hoping it would be easier than this but at least this works.
Inspired by the "inspect the Qt source code and adapt" approach, this worked for me with Qt 5.12:
if (auto grid = dynamic_cast<QGridLayout*>(msgBox.layout())) {
if (auto text = grid->itemAtPosition(0, grid->columnCount() - 1); text && text->widget()) {
text->widget()->setFixedWidth(500);
}
}
Keep in mind, of course, that this will break if ever they change the way they do layouts of QMessageBox.

cocos2d-x 3 add a Sprite into a Layout

When I do this it works:
Layout* layout = Layout::create();
layout->setLayoutType(Layout::Type::HORIZONTAL);
layout->setContentSize(Size(280, 150));
layout->setPosition(Vec2(visibleOrigin.x + 100, visibleOrigin.y + visibleSize.height - 100));
addChild(layout);
auto jacket = Button::create("jacket.png", "jacket.png", "jacket.png", Widget::TextureResType::PLIST);
layout->addChild(jacket);
But when I do this (add a Sprite instead of the button added in above code):
Layout* layout = Layout::create();
layout->setLayoutType(Layout::Type::HORIZONTAL);
layout->setContentSize(Size(280, 150));
layout->setPosition(Vec2(visibleOrigin.x + 100, visibleOrigin.y + visibleSize.height - 100));
addChild(layout);
auto jacket = Sprite::createWithSpriteFrameName("jacket.png");
layout->addChild(jacket);
Then I get assertion fail on line layout->addChild(jacket); with the message Expression: vector subscript out of range. I suppose sprites are not supported in Layouts? Then what is the right way to add and image into a layout? Should I use ImageView as below?
auto jacket = ImageView::create("jacket.png",TextureResType::PLIST);
layout->addChild(jacket);
If yes then why? and what is the difference of Sprite and Image?
if i understand correctly, the button will try to load the individual file named "jacket.png" whereas the createWithSpriteFrameName initializer will try to get the jacket.png frame from a previously loaded texture atlas
The problem could be as simple as the jacket image not being in a texture atlas or the atlas (frames) not being loaded before running this code

Making charts in RaphaelJS that are 100% width?

I have seen graphs in Flash & stuff that basically adapt nicely to whatever the size of the browser or flexible element they are inside of.... I'm not really too well versed with raphaelJS but can you do this, and if so, how?
In raphaeljs, you can call .setSize on a Raphael object to update its size. To adapt to runtime changes in browser window size, you can respond to a window resize event. Using jQuery, you could do:
// initialize Raphael object
var w = $(window).width(),
h = $(window).height();
var paper = Raphael($("#my_element").get(0), w,h);
$(window).resize(function(){
w = $(window).width();
h = $(window).height();
paper.setSize(w,h);
redraw_element(); // code to handle re-drawing, if necessary
});
This will get you a responsive SVG
var w = 500, h=500;
var paper = Raphael(w,h);
paper.setViewBox(0,0,w,h,true);
paper.setSize('100%', '100%');
Normally you could set the width to %100 and define a viewBox within SVG. But, Raphael JS manually set a width and height directly on your SVG elements, which kills this technique.
Bosh's answer is great, but it was distorting the aspect ratio for me. Had to tweak a few things to get it working correctly. Also, included some logic to maintain a maximum size.
// Variables
var width;
var height;
var maxWidth = 940;
var maxHeight = 600;
var widthPer;
function setSize() {
// Setup width
width = window.innerWidth;
if (width > maxWidth) width = maxWidth;
// Setup height
widthPer = width / maxWidth;
height = widthPer * maxHeight;
}
var paper = Raphael(document.getElementById("infographic"), 940, 600);
paper.setViewBox(0, 0, 940, 600, true);
window.onresize = function(event) {
setSize();
paper.setSize(width,height);
redraw_element();
}