• Как в этом примере работает принцип метода replace()?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    С помощью регулярных выражений вычленяется расширение файла (/(\.\w{3,4}$)/ на языке шумеров означает: "в конце строки, слово из 3-4 символов после точки") и с помощью метода replace к перед ним добавляется префикс _h.

    Шумерский алфавит
    \. - это просто точка
    \w{от, до} - это любое слово (набор букв), длиной от-до символов.
    $ - означает конец строки
    ( ) - круглые скобки образуют группы, на которые можно потом сослаться, как $1...$N, по порядку.

    imgFile.replace(imgExt, '_h$l') - Таком образом мы предлагаем заменить группу на нее же, но с префиксом перед ней.
    Ответ написан
    Комментировать
  • Как писать много кода, оставляя его простым, как в начале?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Необходимо развивать абстракцию в коде. Чтобы думать о том "что эта штука умеет?", а не "как это работает?". Кроме того, это избавляет эффекта бабочки (от изменения в одной строчке перестает работать все остальное), разделяя сферы ответственности.

    Да, инфраструктурного кода станет еще больше, но чтобы понимать работу системы в целом будет не обязательно держать в голове механизмы тысячи черных ящиков, достаточно знать, как выглядят интерфейсы основных сервисов. Если же нужно углубиться - изучаем отдельный, независимый уровень сервиса.
    Ответ написан
    5 комментариев
  • Зачем делают так много методов в классе?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Потому что в будущем вы сможете безболезненно добавить логику в метод (получение значения из конфига, из базы, вызов проверки авторизации и т.п., для сеттера - валидация данных). Если же у вас будет голое поле, то придется изменять клиентский код, а это нарушает абстракцию.

    Правило хорошего тона: API класса должен быть доступен только через методы или properties (что, по сути - синтаксический сахар над методами), а поля должны быть только private/protected.
    Ответ написан
    1 комментарий
  • Есть ли в Visual Studio HTML конструктор?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Web Forms - это фреймворк для ASP.NET, где для каждого контрола индивидуально можно писать обработчики на сервере.

    А визуальный конструктор для HTML бестолковый, но есть. Вам нужно открыть окошко View->Toolbox (Ctrl+W, X)580ba78fafcf459b964fa65e2fe0415b.png
    Не руками же html-теги набивать.

    Можно и не руками, а с помощью серверных технологий - того же ASP.NET Web Forms или ASP.NET MVC. Но первую (где целью ставилось максимально оградить разработчика от фронта) за это люто критикуют, а вторая (где были html-хэлперы, хотя у разработчика максимум контроля за разметкой) плавно от этого отходит в пользу кастомных атрибутов (Tag Helpers в ASP.NET Core).

    Так что, да, набивать HTML нужно именно руками. И не только его, но и CSS, который вам все равно не дадут редактировать в окошках Properties, как это было с XAML.
    Ответ написан
    2 комментария
  • Как понять почему падает Qt программа?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Логгирование.
    Ответ написан
  • Где почитать про использование GraphQL c ASP.NET MVC?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Ответ написан
    Комментировать
  • Как передать данные в Layout из Html.RenderAction?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    У вас перепутана последовательность картиночек: Layout зовет экшн Auth-контроллера, а тот, в свою очередь, вызывает GetUser-вьюху и вставляет ее на место вызова в Layout (1 - 3 - 2)

    Тем не менее, ViewBag- это индивидуальное свойство каждого контроллера (BaseController). То есть они разные для Auth-контроллера и того, который зовет Layout (назовем его X) и ваша задумка не прокатит.

    Вы пытаетесь бизнес-логику вытащить на вьюхи.
    Это нужно получать не с помощью отдельного экшна и вьюхи Auth-контроллера, а от сервиса (в который обернуть работу с базой). Затем протягивать этого через вью-модель экшна X-контроллера.
    Ответ написан
    2 комментария
  • На что указывают указатели?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Указатель указывает на базовый адрес (первый байт) экземпляра типа. В вашей структуре там лежит член hp типа int, его адрес совпадает с базовым. Он занимает sizeof(int) байт. То есть color находится по адресу базовый адрес + sizeof(int). Следующий член idCar находится по адресу базовый адрес + sizeof(int) + sizeof(string) и так далее. Но на это полагаться опасно, т.к. существует такое понятие, как выравнивание: часто операционные системы выравнивают данные по границе машинного слова. Т.е. если в нашей архитектуре машинное слово - 4 байта, а член структуры занимает 3 байта (char[3]), то будет добавлено пустое пространство в 1 байт и следующий член разместится по адресу адрес char-массива + sizeof(char[3]) + 1

    Тип указателя определяет, на какое количество байт будет происходить смещение указателя при адресной арифметике. Т.е. char* смещается на 1 байт, int* (при sizeof(int) == 4) на 4 байта, к void* адресную арифметику применять нельзя, потому что его размер нам неизвестен.
    Ответ написан
    Комментировать
  • Как записать мнимую единицу?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Ответ написан
    Комментировать
  • Самый простой способ вызова функции в QT?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Наследование стоит применять тогда, когда вам нужен доступ к состоянию и детальным событиям. Для обработки нажатия достаточно прицепить ваш обработчик на сигнал QPushButton::clicked:

    auto btn = new QPushButton("click me!");
    
    QObject::connect(btn, &QPushButton::clicked, []() { 
    // создание диалога и вызов его в модальном режиме (через QDialog::exec)
    });
    //-----------------------------------
    void myFoo() { }
    
    auto btn = new QPushButton("click me!");
    QObject::connect(btn, &QPushButton::clicked, myFoo);

    UPD: В вашем случае можно сделать примерно так:
    auto btn = new QPushButton("click me!");
    
    QObject::connect(btn, &QPushButton::clicked, []() { 
        ::updateTable(table);
    });
    Ответ написан
  • Правила игнорирования в .gitignore - как сохранить структуру пустых вложенных папок?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Гит не отслеживает папки. Единственный вариант - класть туда пустые файлы.
    Ответ написан
    Комментировать
  • Как парсить json на C#?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Есть достаточно популярная библиотека библиотека Json.NET от Newtonsoft.
    Ответ написан
    5 комментариев
  • Как лучше реализовать цепочку вызовов действий одного класса?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Это называется "fluent interface" или "method chaining".

    Все зависит от того, что вам нужно:

    В jQuery/JS или LINQ/C# возвращаются именно новые объекты.

    Хотя в том же EntityFramework есть Fluent API, где методы вызываются на некотором объекте контекста, который настраивается такой цепочкой. В этом случае лучше возвращать ссылку, как это принято делать при перегрузке операторов.
    Ответ написан
    1 комментарий
  • Как правильно выводить информацию из QVector?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Откройте для себя Model/View в Qt. В частности, ваша задачка с каталогами описана здесь.

    Вкратце: у вас есть модель, в котором вы связываете ваш способ хранения (QVector в вашем случае) со стандарным интерфейсомQAbstractItemModel (или его потомки QAbstractListModel, QAbstractTableModel или QAbstractTreeModel), который можно передать в один из стандартных вью-виджетов (QListView, QTableView, QTreeView). Реализовав интерфейс (переопределив виртуальные методы data и setData для role==Qt::DisplayRole и Qt::EditRole), вы можете просто изменять состояние модели, а вью-виджеты подхватят изменения автоматически.

    Кроме того, есть еще такая штука - QDataWidgetMapper. Он умеет привязывать виджеты (даже обычные, не View) к определенным полям в модели.
    Пример

    Пример объемный, но минимально полный, содержащий всю необходимую инфраструктуру. Допустим, мы хотим создать редактор для некоторых статей (блога?). Нам нужен простой класс Article, чтобы собрать в кучу данные о каждой отдельной статье:

    class Article
    {
    public:
        Article(int id, const QString& title, const QString& content) 
            : _id(id), _title(title), _content(content) {}
    
        int id() const { return _id; } 
        void setId(int id) { _id = id; }
    
        QString title() const { return _title; } 
        void setTitle(const QString& title) { _title = title; }
    
        QString content() const { return _content; }
        void setContent(const QString& content) { _content = content; }
    
    private:
        int     _id;
        QString _title;
        QString _content;
    };

    Для него напишем модель хранения этих статей - ArticlesModel, содержащей массив статей и методы для их добавления/удаления. Кроме того, для нее мы реализуем стандартный интерфейс QAbstractTableModel (методы rowCount, columnCount, data и setData), чтобы виджеты знали, как оттуда брать и как обновлять данные.

    class ArticlesModel :
            public QAbstractTableModel
    {
    public:
        ArticlesModel(QObject *parent=nullptr);
    
        void addArticle(const Article& art);
        void removeArticle(int id);
    
        //QAbstractTableModel interface implamentation
        int rowCount(const QModelIndex &/*parent*/) const override;
        int columnCount(const QModelIndex &/*parent*/) const override;
    
        bool data(QModelIndex& index, const QVariant &value, int role) const override;
        QVariant setData(QModelIndex& index, int role) override;
        
    private:
        std::vector<Article> _articles;
    };
    
    // =================================================================
    
    ArticlesModel(QObject *parent/*=nullptr*/) 
        : QAbstractTableModel(parent)
    {
    }
    
    void ArticlesModel::addArticle(const Article& art) {
        _articles.push_back(art);
    }
    void ArticlesModel::removeArticle(int id) {
        auto found = std::find_if(begin(_articles), end(_articles), 
                                [id](const Article& art) {
                                    art.id() == id;
                                });
        if (found != std::end(_articles)) {
            _articles.erase(artIt);
        }
    }
    
    
    int ArticlesModel::rowCount(const QModelIndex &/*parent*/) const override {
        return _articles.size();
    }
    int ArticlesModel::columnCount(const QModelIndex &/*parent*/) const override {
        return 2;
    }
    
    bool ArticlesModel::data(QModelIndex& index, const QVariant &value, int role) const override {
        if (!index.isValid) return QVariant();
    
        if (role == Qt::EditRole) {
            switch (column) {
                case 0: 
                    QVariant(_articles[index.row()].setTitle(value.toString()));
                    return true; 
                case 1:
                    QVariant(_articles[index.row()].setContent(value.toString()));
                    return true; 
            }
        }
        return false;
    }
    
    QVariant ArticlesModel::setData(QModelIndex& index, int role) override {
        if (!index.isValid) return QVariant();
    
        if (role == Qt::DisplayRole || role == Qt::EditRole) {
            switch (column) {
                case 0: return QVariant(_articles[index.row()].title()); 
                case 1: return QVariant(_articles[index.row()].content());
            }
        }
        return QVariant();
    }


    Тогда можно сделать так:

    // this - это какой-то родительский виджет
    
    auto titleEditor = new QLineEdit(this);
    auto contentEditor = new QTextEdit(this);
    
    QAbstractTableModel *model = new ArticlesModel(this);
    model->addArticle(Article(1, "Hello title", "Hello content"));
    model->addArticle(Article(2, "Another title", "Another content"));
    
    auto mapper = new QDataWidgetMapper(this);
    mapper->setModel(model);
    mapper->addMapping(titleEditor, 0);
    mapper->addMapping(contentEditor, 1);
    mapper->toFirst(); // Переключаемся на первый элемент модели


    Теперь мы можем добавлять/удалять статьи в model->add/removeArticle(const Article&), переходить с заметки на заметку с помощью mapper->setCurrentIndex(int index), менять содержимое заметок в редакторе.

    Можно добавить QListView, так же передать туда модель через setModel() и связать сигнал изменения текущего элемента списка с тем же действием mapper, добавить пару кнопок для добавления/удаления заметок и мы получим полноценный редактор.
    Ответ написан
    Комментировать
  • Есть ли в природе актуальная литература по C++?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    #include "stdafx.h"вроде должен быть первым в файле.
    В студии вам пока лучше создавать пустой проект, чтобы подобные штуки не мешали.

    c8ea5745f7ad47b481e100046e1e27b2.png

    Учитывая, что C++ поддерживает обратную совместимость, то любая, более или менее современная книжка (начиная с C++03, т.е. 2003 года) для вас будет актуальна. Да и вообще, стоило бы поискать K&R и овладевать Си.
    Ответ написан
    3 комментария
  • Каким образом можно создать кастомное окно в программе?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Для форм:

    this.BackgroundImage = //Image
    this.FormBorderStyle = FormBorderStyle.None;
    this.Width = this.BackgroundImage.Width;
    this.Height = this.BackgroundImage.Height;
    this.TransparencyKey = Color.FromArgb(0, 255, 0); //Contrast Color


    Для WPF
    Ответ написан
    3 комментария
  • Что должен знать Junior C++ программист на данный момент?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Все на свете, причем еще и зависит от рода деятельности. Можно не слишком глубоко, но в общих чертах знать куда идти, в случае чего. Из популярного - STL, WinAPI, COM, Boost, кое-где Qt. Увы, но порог вхождения там высок, да еще и необходимо "затачиваться" на конкретную вакансию. Ибо embedded, системное и прикладное программирование - это разные вещи, которые требуют различных знаний.

    Мне кажется, что в этой Спарте нет джуниоров, там сразу хорошие миддлы =)
    Ответ написан
    Комментировать
  • Стоит ли учить сегодня ASP.NET и можно ли на этом заработать?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Начнем с терминологии, а то хейтеры тут не особо разбираются =) Между ASP и ASP.NET MVC разница примерно такая же, как между Java и JavaScript.
    Java - это язык, как и C#. Под них есть свои веб-фреймворки, такие как JavaEE, Spring для Java или ASP.NET MVC, NancyFX для C#.


    Учить ASP (classic ASP) или ASP.NET (который Web Forms) с нуля уже не стоит. А вот ASP.NET MVC - отличный выбор. Это уже достаточно зрелый фреймворк, на котором работает много серьезных проектов (таких, как StackOverflow) и которая востребована на рынке как в России, так и в мире.

    Сам C# достаточно интересный, активно развивающийся язык. Платформа себя чувствует неплохо на любых популярных устройствах. Хорошо развивается .NET Core, являющийся переосмыслением монолитного .NET Framework, позволяющий разрабатывать компатные кросслатформенные приложения, в том числе и с использованием ASP.NET Core, которые можно развертывать самостоятельно, без огромного сервера за спиной, аналогично Node.js.

    Конечно, с ASP.NET MVC не пофрилансишь и сайты-визитки разрабатывать не так удобно =) Но поддерживать крупные приложения - одно удовольствие.

    А Java - это уже такой динозаврик, который стагнирует в роли вечного догоняющего, потихоньку будет сходить на нет в ближайшее десятилетие. Да, платформа обеспечила себя специалистами, тоннами легаси-проектов, которые необходимо поддерживать, поэтому с работой и под нее проблем не будет и менеджеры часто выбирают эту штуку, как проверенное десятилетиями средство. Но с точки зрения обычного программиста, я не вижу смысла выбирать Java.
    Ответ написан
    3 комментария
  • Как хранить ветки GIT в разных папках?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Чтобы хранить разные ветки в разных папках вы можете склонировать один и тот же репозиторий в две разные папки, в каждом из получившихся локальных репозиториев переключиться на нужную ветку. Но смысла в этом нет никакого, ибо это переключаться достаточно просто и безболезненно с помощью checkout и stash.

    Но обычно для таких общих фиксов для веток, которые не планируют сливать, заводят отдельную ветку от общего родителя (если это возможно), коммитят в нее фиксы и подмерживают в ветки, где эти изменения нужны.

    Если так сделать нельзя (слишком давно отбранчевались от родителя и мержить будет сложно), то можно коммитить в оду из веток, но в другую не мержить ее всю напрямую, а перенести лишь новые коммиты с помощью команды cherry pick.
    Ответ написан
    1 комментарий