質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.58%

表示領域の端をクリックした時自動でスケールを変えたい

受付中

回答 0

投稿

  • 評価
  • クリップ 0
  • VIEW 883

score 12

 前提・実現したいこと

C++でデータの読み込み, 追加, 書き出しを行うプログラムを作っています.
実行時の表紙領域の端側をクリックした時に自動でスケールが変わる仕様にしたいと考えています.

 発生している問題

自分で行ったソースの変更では上や右へのスケール変更は成功したが,
左や下へのスケール変更が行われません.

 該当のソースコード

#include <gtkmm/application.h>

#include "MyWindow.h"

int main( ){
    auto app = Gtk::Application::create( );
    ClusteringDataApp::MyWindow myWindow;

    return app->run( myWindow );
}
#include "MyWindow.h"

namespace ClusteringDataApp{
    MyWindow::MyWindow( ) :
        openButton_( "LOAD" ), saveButton_( "SAVE&EXIT" ), data_( 0 ), drawingArea_( data_ ) {

        set_border_width( 5 );
        openButton_.signal_clicked( ).connect(
            sigc::mem_fun( *this, &MyWindow::on_openButton_clicked )
            );
        saveButton_.signal_clicked( ).connect(
            sigc::mem_fun( *this, &MyWindow::on_saveButton_clicked )
            );
        vBox_.pack_start( openButton_, false, true );
        drawingArea_.set_size_request( 600, 600 );
        vBox_.pack_start( drawingArea_, true, true );

        add( vBox_ );
        show_all( );
    }

    void MyWindow::on_openButton_clicked( ){
        data_.clear( );
        Gtk::FileChooserDialog dialog( *this, "Load from", Gtk::FILE_CHOOSER_ACTION_OPEN  );
        dialog.add_button( Gtk::Stock::OPEN, Gtk::RESPONSE_OK );
        dialog.add_button( Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL );

        auto filterText = Gtk::FileFilter::create( );
        filterText->set_name( "プレーンテキスト" );
        filterText->add_pattern( "*.txt" );
        dialog.add_filter( filterText );

        if( Gtk::RESPONSE_OK == dialog.run( ) ){
            std::string dataFileName = dialog.get_filename( );

            auto ifs = std::ifstream( dataFileName, std::ios::in );
            while( ifs.good( ) ){
                std::string aLine;
                std::getline( ifs, aLine );
                std::istringstream iss( aLine );

                std::vector<double> lineData;
                double temp;
                while( iss >> temp ) lineData.push_back( temp );

                if( !lineData.empty( ) )
                    data_.emplace_back( std::make_pair( lineData.at( 0 ), lineData.at( 1 ) ) );
            }
        }
        if( !data_.empty( ) ){
            vBox_.remove( openButton_ );
            vBox_.pack_end( saveButton_, false, true );
            saveButton_.show( );
        }
    }

    void MyWindow::on_saveButton_clicked( ){
        const std::string fileName = "newData.txt";
        std::cerr << data_.size( ) << " data is written to " << fileName << "\n";

        auto ofs = std::ofstream( fileName, std::ios::out );
        if( ofs.good( ) )
            for( const auto& pair : data_ )
                ofs << pair.first << "\t" << pair.second << "\n";
        ofs.close( );

        hide( );
    }
}
#ifndef MYWINDOW_INCLUDED
#define MYWINDOW_INCLUDED
#include <gtkmm/window.h>
#include <gtkmm/button.h> 
#include <gtkmm/hvbox.h> 
#include <gtkmm/filechooserdialog.h>
#include <gtkmm/stock.h>
#include <gtkmm/filefilter.h>
#include <giomm.h>

#include <iostream>
#include <vector>
#include <utility> 
#include <fstream>
#include <string>
#include <sstream>

#include "MyDrawingArea.h"
namespace ClusteringDataApp{
    class MyWindow : public Gtk::Window{
    public:
        MyWindow( );
        virtual ~MyWindow( ) = default;

    protected:
        virtual void on_openButton_clicked( );
        virtual void on_saveButton_clicked( );

        Gtk::Button openButton_;
        Gtk::Button saveButton_;
        Gtk::VBox vBox_;

        dataType< > data_;

        MyDrawingArea drawingArea_; 
    };
}
#endif
#include "MyDrawingArea.h"

namespace ClusteringDataApp{
    MyDrawingArea::MyDrawingArea( dataType< >& data ) :
        data_( data ){
        add_events( Gdk::BUTTON_PRESS_MASK );
    }

    void MyDrawingArea::prepareProperties( ) {
        minMaxPairForX0_ = std::minmax_element( data_.cbegin( ), data_.cend( ),
            [ ]( const std::pair< double, double >& a, const std::pair< double, double >& b ){
                return a.first > b.first;
            } );
        minMaxPairForX1_ = std::minmax_element( data_.cbegin( ), data_.cend( ), 
            [ ]( const std::pair< double, double >& a, const std::pair< double, double >& b ){
                return a.second > b.second;
            } );

        width_ = get_width( );
        height_ = get_height( );
    }

    bool MyDrawingArea::on_draw( const Cairo::RefPtr<Cairo::Context>& cr ){
        if( 0 == data_.size( ) ) return false;

        prepareProperties( );
        auto x0band = (*minMaxPairForX0_.first).first - (*minMaxPairForX0_.second).first;
        auto x1band = (*minMaxPairForX1_.first).second - (*minMaxPairForX1_.second).second;

        auto f0 = [ & ]( double x ){
            return ( x - (*minMaxPairForX0_.second).first ) * width_ / x0band; };
        auto f1 = [ & ]( double x ){
            return height_ - ( x - (*minMaxPairForX1_.second).second ) * height_ / x1band; };

        cr->set_source_rgb( 1., 1., .8 ); // LIGHT YELLOW
        cr->rectangle( 0.,0., width_, height_ );
        cr->fill( );

        cr->set_source_rgb( 1., 0., 0. ); // RED
        for( const auto& pair : data_ ){
            cr->arc(
                f0( pair.first ), f1( pair.second ), 
                3., 0., 2. * G_PI ); // size 3. circle
            cr->fill( );
        }
        return false;
    }

    bool MyDrawingArea::on_button_press_event( GdkEventButton* event ){
        if( 0 == data_.size( ) ) return false;

        prepareProperties( );
        auto x0band = (*minMaxPairForX0_.first).first - (*minMaxPairForX0_.second).first;
        auto x1band = (*minMaxPairForX1_.first).second - (*minMaxPairForX1_.second).second;

        auto f0 = [ & ]( double x ){ 
            return (*minMaxPairForX0_.second).first + x * x0band / width_; };
        auto f1 = [ & ]( double x ){ 
            return  x1band * ( height_ - x ) / height_ + (*minMaxPairForX1_.second).second; };

        if( ( event->type == GDK_BUTTON_PRESS ) && ( event->button == 1 ) )
            data_.emplace_back( f0( event->x ), f1( event->y ) ); 

        queue_draw( );
        return false;
    }
}
#ifndef MYDRAWINGAREA_INCLDED
#define MYDRAWINGAREA_INCLDED
#include <gtkmm/drawingarea.h>

#include <vector>
#include <utility> // std::pair
#include <algorithm>

namespace ClusteringDataApp{
    template < typename T = double >
    using dataType = std::vector< std::pair<T, T> >;

    class MyDrawingArea : public Gtk::DrawingArea{
    public:
        explicit MyDrawingArea( dataType< >& data );
        virtual ~MyDrawingArea( ) = default;

    protected:
        bool on_draw( const Cairo::RefPtr<Cairo::Context>& cr ) override;
        bool on_button_press_event( GdkEventButton* event ) override;

    private:
        void prepareProperties( );

        dataType< >& data_;

        std::pair< 
            dataType< >::const_iterator, 
            dataType< >::const_iterator >  minMaxPairForX0_, minMaxPairForX1_;

        double width_, height_;
    };
}
#endif

 試したこと

MyDrawingArea.cppを

    bool MyDrawingArea::on_draw( const Cairo::RefPtr<Cairo::Context>& cr ){
        if( 0 == data_.size( ) ) return false;


        auto x0band = (*minMaxPairForX0_.first).first - (*minMaxPairForX0_.second).first/1.2;
        auto x1band = (*minMaxPairForX1_.first).second - (*minMaxPairForX1_.second).second/1.2;
    bool MyDrawingArea::on_button_press_event( GdkEventButton* event ){
        if( 0 == data_.size( ) ) return false;

        prepareProperties( );
        auto x0band = (*minMaxPairForX0_.first).first - (*minMaxPairForX0_.second).first/1.2;
        auto x1band = (*minMaxPairForX1_.first).second - (*minMaxPairForX1_.second).second/1.2;


に変更したところ,発生している問題と同様の状態になりました.
このような挙動をするように左側,下側へスケール変更が行われるようにしたいです.

 補足情報(FW/ツールのバージョンなど)

開発は,統合開発環境のvscodeを用いており,cppは11を利用しています.

どうかご助力いただけると助かります.
おそらくMyDrawingArea.cppを変更すればいいと思うのですが...

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正の依頼

  • yuki23

    2018/09/18 19:27

    GTK+ をタグに入れたほうがいいかもしれません

    キャンセル

  • yoshiki0424yi

    2018/09/18 22:23

    承知しました。ありがとうございます。

    キャンセル

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.58%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る